ukui-interface/0000775000175000017500000000000015167726076012434 5ustar fengfengukui-interface/src/0000775000175000017500000000000015167726076013223 5ustar fengfengukui-interface/src/Makefile.am0000664000175000017500000000004415167726076015255 0ustar fengfengNULL = SUBDIRS = common \ $(NULL) ukui-interface/src/common/0000775000175000017500000000000015167726076014513 5ustar fengfengukui-interface/src/common/Makefile.am0000664000175000017500000000246215167726076016553 0ustar fengfeng#Generata binary file lib_LTLIBRARIES = libukui-com4c.la libukui-com4cxx.la #gcc -wall: displays all the errors and warning information when compiling #gcc -g: add the debugging code when compiling COMM_CFS = -Wall -g #Add the dependent source file for libukui-com4c.la libukui_com4c_la_SOURCES = kylin-com4c.c \ kylin-ini.c \ $(NULL) #Additional C compiler flags libukui_com4c_la_CFLAGS= $(COMM_CFS) \ -liniparser \ $(NULL) #Additional link objects libukui_com4c_la_LDFLAGS= \ $(NULL) #Add the dependent source file for libukui-com4cxx.la libukui_com4cxx_la_SOURCES = kylin-com4cxx.cpp \ kylin-ini.c \ $(NULL) #Additional CXX compiler flags libukui_com4cxx_la_CXXFLAGS= $(COMM_CFS) \ -liniparser \ $(NULL) #Additional C compiler flags libukui_com4cxx_la_CFLAGS= $(COMM_CFS) \ $(NULL) #Additional link objects libukui_com4cxx_la_LDFLAGS= \ $(NULL) #The header files that need to be installed include_HEADERS= \ kylin-com4c.h \ kylin-com4cxx.h \ $(NULL) #Additional C compiler flags libukui_gsettings_la_CFLAGS= $(COMM_CFS) \ $(GLIB_2_CFLAGS) $(GIO_2_CFLAGS) $(GIO_UNIX_2_CFLAGS) \ $(NULL) #Additional link objects libukui_gsettings_la_LDFLAGS= \ $(GLIB_2_LIBS) $(GIO_2_LIBS) $(GIO_UNIX_2_LIBS) \ $(NULL) ukui-interface/src/common/kylin-com4c.h0000664000175000017500000000564015167726076017022 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see #ifdef __cplusplus extern "C" { #endif /** * @fn kdk_get_lsbrelease * @brief 根据lsbrelease信息的键获取值 * @param[in] key lsbrelease信息的键 * @param[out] value lsbrelease信息的值 * @param[in] value_max_len 值缓存区的大小 * @retval int > 0 成功 否则失败 */ int kdk_get_lsbrelease(const char *key, char *value, int value_max_len); /** * @fn kdk_get_osrelease * @brief 根据osrelease信息的键获取值 * @param[in] key osrelease信息的键 * @param[out] value osrelease信息的值 * @param[in] value_max_len 值缓存区的大小 * @retval int > 0 成功 否则失败 */ int kdk_get_osrelease(const char *key, char *value, int value_max_len); /** * @fn kdk_get_kyinfo * @brief 根据kyinfo的键获取值 * @param[in] session kyinfo的session值 * @param[in] key kyinfo的键 * @param[out] value kyinfo的值 * @param[in] value_max_len 值缓存区的大小 * @retval int >= 0 成功 否则失败 */ int kdk_get_kyinfo(const char *session, const char *key, char *value, int value_max_len); /** * @fn kdk_get_prjcodename * @brief 根据PROJECT_CODENAME字段的值 * @param[out] value PROJECT_CODENAME字段的值 * @param[in] value_max_len 值缓存区的大小 * @retval int > 0 成功 否则失败 */ int kdk_get_prjcodename(char *value, int value_max_len); /** * @fn kdk_get_cpumodelname * @brief 获取CPU型号 * @param[out] modelName CPU型号信息 * @param[in] max_len CPU型号缓存区的大小 * @retval int > 0 成功 否则失败 */ int kdk_get_cpumodelname(char *modelName, int max_len); /** * @fn kdk_get_spechdplatform * @brief 获取特定硬件平台信息 * @param[out] platformName 特定硬件平台信息 * @param[in] max_len 特定硬件平台缓存区的大小 * @retval int > 0 成功 否则失败 */ int kdk_get_spechdplatform(char *platformName, int max_len); /** * @fn kdk_get_virtenv * @brief 获取虚拟化环境 * @param[out] virtenv 虚拟化环境标志 * @param[in] max_len 虚拟化环境标志缓存区的大小 * @retval int > 0 成功 否则失败 */ int kdk_get_virtenv(char *virtenv, int max_len); #ifdef __cplusplus } #endif #endif // __KYLINCOMM4C_H__ ukui-interface/src/common/kylin-ini.c0000664000175000017500000000462515167726076016571 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see #include #include #include //去除尾部空白字符 包括\t \n \r /* 标准的空白字符包括: ' ' (0x20) space (SPC) 空格符 '\t' (0x09) horizontal tab (TAB) 水平制表符 '\n' (0x0a) newline (LF) 换行符 '\v' (0x0b) vertical tab (VT) 垂直制表符 '\f' (0x0c) feed (FF) 换页符 '\r' (0x0d) carriage return (CR) 回车符 //windows \r\n linux \n mac \r */ char *strstripr(char *str, int containQuot) { if(str == NULL || *str == '\0') { return str; } int len = s_strcount(str); char *p = str + len - 1; if (containQuot) { while(p >= str && (isspace(*p) || *p == '\"')) { *p = '\0'; --p; } } else { while(p >= str && isspace(*p)) { *p = '\0'; --p; } } return str; } //去除首部空格 char *strstripl(char *str, int containQuot) { if(str == NULL || *str == '\0') { return str; } int len = 0; char *p = str; if (containQuot) { while(*p != '\0' && (isspace(*p) || *p == '\"')) { ++p; ++len; } } else { while(*p != '\0' && isspace(*p)) { ++p; ++len; } } size_t left_len = s_strcount(str) - len + 1; memmove(str, p, left_len); return str; } //去除首尾空格 char *strstrip(char *str, int containQuot) { str = strstripr(str, containQuot); str = strstripl(str, containQuot); return str; } // 安全计算字符串长度 size_t s_strcount(const char *str) { char dest[256] = {0}; strncpy(dest, str, sizeof(dest)); dest[sizeof(dest) - 1] = 0; return strlen(dest); } ukui-interface/src/common/kylin-com4cxx.h0000664000175000017500000000470415167726076017402 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see using namespace std; #ifdef __cplusplus extern "C" { #endif /** * @fn KDKGetLsbRelease * @brief 根据lsbrelease信息的键获取值 * @param[in] key lsbrelease信息的键 * @param[out] value lsbrelease信息的值 * @param[in] value_max_len 值缓存区的大小 * @retval string lsbrelease信息的值,empty 失败,否则成功 */ string KDKGetLSBRelease(const string key); /** * @fn KDKGetOSRelease * @brief 根据osrelease信息的键获取值 * @param[in] key osrelease信息的键 * @retval string osrelease信息的值,empty 失败,否则成功 */ string KDKGetOSRelease(const string key); /** * @fn KDKGetKYInfo * @brief 根据kyinfo的键获取值 * @param[in] session kyinfo的session值 * @param[in] key kyinfo的键 * @retval string kyinfo信息的键值,empty 失败,否则成功 */ string KDKGetKYInfo(const string session, const string key); /** * @fn KDKGetPrjCodeName * @brief 根据PROJECT_CODENAME字段的值 * @param None 无参 * @retval string PROJECT_CODENAME字段的值,empty 失败,否则成功 */ string KDKGetPrjCodeName(); /** * @fn KDKGetCpuModelName * @brief 获取CPU型号 * @param None 无参 * @retval string CPU型号信息,empty 失败,否则成功 */ string KDKGetCpuModelName(); /** * @fn KDKGetSpecHDPlatform * @brief 获取特定硬件平台信息 * @param None 无参 * @retval string 特定硬件平台信息,empty 失败,否则成功 */ string KDKGetSpecHDPlatform(); /** * @fn KDKGetVirtEnv * @brief 获取虚拟化环境 * @param None 无参 * @retval string 虚拟化环境标志信息,empty 失败,否则成功 */ string KDKGetVirtEnv(); #ifdef __cplusplus } #endif #endif // __KYLINCOMM4C_H__ ukui-interface/src/common/kylin-ini.h0000664000175000017500000000222115167726076016564 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see #include #ifdef __cplusplus extern "C" { #endif // 去除尾部空格 char *strstripr(char *str, int containQuot); // 去除头部空格 char *strstripl(char *str, int containQuot); // 去除前后空格 char *strstrip(char *str, int containQuot); // 安全计算字符串长度 size_t s_strcount(const char *str); #ifdef __cplusplus } #endif #endif //__KYLININI_H__ ukui-interface/src/common/kylin-com4c.c0000664000175000017500000001634715167726076017023 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see #include #include #include #include #include "kylin-ini.h" #define LSB_RELEASE_FILE "/etc/lsb-release" /* lsb-release文件路径 */ #define OS_RELEASE_FILE "/etc/os-release" /* os-release文件路径 */ #define KYINFO_FILE "/etc/.kyinfo" /* kyinfo文件路径 */ #define CPUINFO_FILE "/proc/cpuinfo" /* cpuinfo文件路径 */ #define RELEASEFILE_LINE_MAX 256 /* 最大解析行行数 */ #define RELEASEFILE_LINE_MAX_LEN 256 /* 最大解析行长度 */ #define RELEASEFILE_KEY_MAX_LEN 128 /* 最大key长度 */ #define RELEASEFILE_VALUE_MAX_LEN 256 /* 最大value长度 预留'\0', '='*/ #define RELEASEFILE_SPLIT_EQUAL '=' /* key和value的分隔符 */ #define RELEASEFILE_SPLIT_COLON ':' /* key和value的分隔符 */ #define PROJECT_CODENAME "PROJECT_CODENAME" #define CPUINFO_MODELNAME "model name" // 根据key获取value,成功返回 >0 否则 返回 <= 0 static int file_get_keyvalue(const char *path, const char *key, char *value, int value_max_len, const char chSplit) { if (path == NULL || key == NULL || value == NULL || value_max_len <= 0) { return -1; } int ret = 0; int cnt = 0; int key_len = 0; int line_len = 0; int value_len = 0; FILE *fp = NULL; char line_buf[RELEASEFILE_LINE_MAX_LEN] = {0}; /* 合法性判断 */ if (NULL == path || NULL == key || NULL == value || 0 >= value_max_len) { return -1; } key_len = s_strcount(key); if (0 >= key_len || RELEASEFILE_KEY_MAX_LEN < key_len) { return -2; } /* 打开文件 */ fp = fopen(path, "r"); if (NULL == fp) { return -4; } /* 遍历行,匹配Key */ while(NULL != fgets(line_buf, RELEASEFILE_LINE_MAX_LEN-1, fp)) { line_len = s_strcount(line_buf); if (line_len > key_len) { /* 找到key */ //找到非空格的首字符 char *pStart = line_buf; int nSplitIndex = 0; while(pStart != (line_buf+line_len) && isspace(*pStart)) { ++pStart; ++nSplitIndex; } if (0 == strncmp(pStart, key, key_len)) { pStart = pStart + key_len; nSplitIndex = nSplitIndex + key_len; //跳过空格字符 while(pStart != (line_buf+line_len) && isspace(*pStart)) { ++pStart; ++nSplitIndex; } if (pStart != (line_buf+line_len) && *pStart == chSplit) { ret = 1; key_len = nSplitIndex; break; } } } memset(line_buf, 0, sizeof(line_buf)); /* 最大查找行限制 */ cnt++; if (RELEASEFILE_LINE_MAX < cnt) { break; } } /* 关闭文件 */ fclose(fp); fp = NULL; /* 找到key,返回value */ memset(value, 0, value_max_len); if (1 == ret) { value_len = line_len - key_len - 1; if (0 < value_len) { if (value_len >= value_max_len) { value_len = value_max_len - 1; } /* 拷贝value */ char *src_buffer = NULL; if (key_len + 1 < RELEASEFILE_LINE_MAX_LEN) { src_buffer = &line_buf[key_len + 1]; } else { src_buffer = "\0"; } snprintf(value, value_max_len, "%s", src_buffer); /* 去掉结尾的换行符 */ strstrip(value, 1); } } return ret; } /** * @fn kdk_get_xdgsessiontype * @brief 获取区分x11与wayland的环境变量值 * @retval char* !NULL 成功 否则失败 */ char* kdk_get_xdgsessiontype() { return getenv("XDG_SESSION_TYPE"); } int kdk_get_lsbrelease(const char *key, char *value, int value_max_len) { int nRet = -1; if (NULL == key || NULL == value || 0 >= value_max_len) return nRet; dictionary *iniHandle = iniparser_load(LSB_RELEASE_FILE); if (iniHandle) { char sessionKey[256] = {0}; snprintf(sessionKey, 256, ":%s", key); const char *tempValue = iniparser_getstring(iniHandle, sessionKey, ""); snprintf(value, value_max_len, "%s", tempValue); iniparser_freedict(iniHandle); iniHandle = NULL; nRet = s_strcount(value); } return nRet; } int kdk_get_osrelease(const char *key, char *value, int value_max_len) { int nRet = -1; if (NULL == key || NULL == value || 0 >= value_max_len) return nRet; dictionary *iniHandle = iniparser_load(OS_RELEASE_FILE); if (iniHandle) { char sessionKey[256] = {0}; snprintf(sessionKey, 256, ":%s", key); const char *tempValue = iniparser_getstring(iniHandle, sessionKey, ""); snprintf(value, value_max_len, "%s", tempValue); iniparser_freedict(iniHandle); iniHandle = NULL; nRet = s_strcount(value); } return nRet; } int kdk_get_prjcodename(char *value, int value_max_len) { int nResult = kdk_get_lsbrelease(PROJECT_CODENAME, value, value_max_len); if (nResult <= 0) { nResult = kdk_get_osrelease(PROJECT_CODENAME, value, value_max_len); } return nResult; } int kdk_get_kyinfo(const char *session, const char *key, char *value, int value_max_len) { int nRet = -1; if (NULL == session || NULL == key || NULL == value || 0 >= value_max_len) return nRet; dictionary *iniHandle = iniparser_load(KYINFO_FILE); if (iniHandle) { char sessionKey[256] = {0}; snprintf(sessionKey, 256, "%s:%s", session, key); const char *tempValue = iniparser_getstring(iniHandle, sessionKey, ""); snprintf(value, value_max_len, "%s", tempValue); iniparser_freedict(iniHandle); iniHandle = NULL; nRet = s_strcount(value); } return nRet; } int kdk_get_cpumodelname(char *modelName, int max_len) { return file_get_keyvalue(CPUINFO_FILE, CPUINFO_MODELNAME, modelName, max_len, RELEASEFILE_SPLIT_COLON); } int kdk_get_spechdplatform(char *platformName, int max_len) { if (platformName == NULL || max_len <= 0) return -1; char strDefault[128] = "default"; int validLen = s_strcount(strDefault); validLen = validLen > max_len ? max_len : validLen; snprintf(platformName, max_len, "%s", strDefault); return validLen; } int kdk_get_virtenv(char *virtenv, int max_len) { if (virtenv == NULL || max_len <= 0) return -1; int validLen = 0; char *cmdStr = "systemd-detect-virt"; // 准备运行的命令 FILE *pipeLine = popen(cmdStr,"r"); // 建立流管道 if (!pipeLine) { // 检测流管道 return -2; } if (fgets(virtenv, max_len, pipeLine) != NULL) { // 获取输出 validLen = s_strcount(virtenv); } else { char strDefault[128] = "none"; validLen = s_strcount(strDefault); validLen = validLen > max_len ? max_len : validLen; snprintf(virtenv, max_len, "%s", strDefault); } pclose(pipeLine); return validLen; } ukui-interface/src/common/kylin-com4cxx.cpp0000664000175000017500000001517315167726076017737 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see #include #include #include #include #include #include "kylin-ini.h" #define LSB_RELEASE_FILE "/etc/lsb-release" /* lsb-release文件路径 */ #define OS_RELEASE_FILE "/etc/os-release" /* os-release文件路径 */ #define KYINFO_FILE "/etc/.kyinfo" /* kyinfo文件路径 */ #define CPUINFO_FILE "/proc/cpuinfo" /* cpuinfo文件路径 */ #define RELEASEFILE_LINE_MAX 256 /* 最大解析行行数 */ #define RELEASEFILE_LINE_MAX_LEN 256 /* 最大解析行长度 */ #define RELEASEFILE_KEY_MAX_LEN 128 /* 最大key长度 */ #define RELEASEFILE_VALUE_MAX_LEN 256 /* 最大value长度 预留'\0', '='*/ #define RELEASEFILE_SPLIT_EQUAL '=' /* key和value的分隔符 */ #define RELEASEFILE_SPLIT_COLON ':' /* key和value的分隔符 */ #define PROJECT_CODENAME "PROJECT_CODENAME" #define CPUINFO_MODELNAME "model name" // 根据key获取value,成功返回 >0 否则 返回 <= 0 static int file_get_keyvalue(const char *path, const char *key, char *value, int value_max_len, const char chSplit) { if (path == NULL || key == NULL || value == NULL || value_max_len <= 0) { return -1; } int ret = 0; int cnt = 0; int key_len = 0; int line_len = 0; int value_len = 0; FILE *fp = NULL; char line_buf[RELEASEFILE_LINE_MAX_LEN] = {0}; /* 合法性判断 */ if (NULL == path || NULL == key || NULL == value || 0 >= value_max_len) { return -1; } key_len = s_strcount(key); if (0 >= key_len || RELEASEFILE_KEY_MAX_LEN < key_len) { return -2; } /* 打开文件 */ fp = fopen(path, "r"); if (NULL == fp) { return -4; } /* 遍历行,匹配Key */ while(NULL != fgets(line_buf, RELEASEFILE_LINE_MAX_LEN-1, fp)) { line_len = s_strcount(line_buf); if (line_len > key_len) { /* 找到key */ //找到非空格的首字符 char *pStart = line_buf; int nSplitIndex = 0; while(pStart != (line_buf+line_len) && isspace(*pStart)) { ++pStart; ++nSplitIndex; } if (0 == strncmp(pStart, key, key_len)) { pStart = pStart + key_len; nSplitIndex = nSplitIndex + key_len; //跳过空格字符 while(pStart != (line_buf+line_len) && isspace(*pStart)) { ++pStart; ++nSplitIndex; } if (pStart != (line_buf+line_len) && *pStart == chSplit) { ret = 1; key_len = nSplitIndex; break; } } } memset(line_buf, 0, sizeof(line_buf)); /* 最大查找行限制 */ cnt++; if (RELEASEFILE_LINE_MAX < cnt) { break; } } /* 关闭文件 */ fclose(fp); fp = NULL; /* 找到key,返回value */ if (1 == ret) { value_len = line_len - key_len - 1; if (0 < value_len) { if (value_len >= value_max_len) { value_len = value_max_len-1; } /* 拷贝value */ char src_buffer[256] = {0}; if (key_len + 1 < RELEASEFILE_LINE_MAX_LEN) { strncpy(src_buffer, &line_buf[key_len + 1], sizeof(src_buffer)); src_buffer[sizeof(src_buffer) - 1] = 0; } else { src_buffer[0] = '\0'; } snprintf(value, value_max_len, "%s", src_buffer); value[value_len] = '\0'; /* 去掉结尾的换行符 */ strstrip(value, 1); } else { value[0] = '\0'; } } return ret; } /** * @fn KDKGetXdgSessionType * @brief 获取区分x11与wayland的环境变量值 * @param None 无参 * @retval string xdg会话类型字符串,empty 失败,否则成功 */ string KDKGetXdgSessionType() { char *strSessionType = getenv("XDG_SESSION_TYPE"); if (!strSessionType) { return ""; } return string(strSessionType); } string KDKGetLSBRelease(const string key) { if (key.empty()) { return ""; } dictionary *iniHandle = iniparser_load(LSB_RELEASE_FILE); if (iniHandle) { string sessionKey = ":"+key; string strValue = ""; strValue = iniparser_getstring(iniHandle, sessionKey.c_str(), ""); iniparser_freedict(iniHandle); iniHandle = NULL; return string(strValue); } return ""; } string KDKGetOSRelease(const string key) { if (key.empty()) { return ""; } dictionary *iniHandle = iniparser_load(OS_RELEASE_FILE); if (iniHandle) { string sessionKey = ":"+key; string strValue = ""; strValue = iniparser_getstring(iniHandle, sessionKey.c_str(), ""); iniparser_freedict(iniHandle); iniHandle = NULL; return string(strValue); } return ""; } string KDKGetPrjCodeName() { string strValue = KDKGetLSBRelease(PROJECT_CODENAME); if (strValue.empty()) { strValue = KDKGetOSRelease(PROJECT_CODENAME); } return string(strValue); } string KDKGetKYInfo(const string session, const string key) { if (session.empty() || key.empty()) { return ""; } dictionary *iniHandle = iniparser_load(KYINFO_FILE); if (iniHandle) { string sessionKey = session+":"+key; string strValue = ""; strValue = iniparser_getstring(iniHandle, sessionKey.c_str(), ""); iniparser_freedict(iniHandle); iniHandle = NULL; return string(strValue); } return ""; } string KDKGetCpuModelName() { char strValue[256] = {0}; int nRet = file_get_keyvalue(CPUINFO_FILE, CPUINFO_MODELNAME, strValue, 256, RELEASEFILE_SPLIT_COLON); if (nRet > 0) { return string(strValue); } else { return ""; } } string KDKGetSpecHDPlatform() { string strDefaultValue = "default"; return string(strDefaultValue); } string KDKGetVirtEnv() { char virtEnv[256] = {0}; string strVirtEnv = ""; char cmdStr[] = "systemd-detect-virt"; // 准备运行的命令 FILE *pipeLine = popen(cmdStr,"r"); // 建立流管道 if (!pipeLine) { // 检测流管道 return strVirtEnv; } if (fgets(virtEnv, 256, pipeLine) != NULL) { // 获取输出 strVirtEnv = virtEnv; } else { strVirtEnv = "none"; } pclose(pipeLine); return string(strVirtEnv); } ukui-interface/src/log4qt/0000775000175000017500000000000015167726076014435 5ustar fengfengukui-interface/src/log4qt/Doxyfile0000664000175000017500000002116615167726064016146 0ustar fengfeng# Doxyfile 1.5.3 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = Log4Qt PROJECT_NUMBER = OUTPUT_DIRECTORY = doc CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 4 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = NO EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = NO HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = NO FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text " WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = INPUT_ENCODING = UTF-8 FILE_PATTERNS = RECURSIVE = YES EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = *_p.h \ *.cpp EXCLUDE_SYMBOLS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES REFERENCES_LINK_SOURCE = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO HTML_DYNAMIC_SECTIONS = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = YES EXPAND_ONLY_PREDEF = YES SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = Q_CORE_EXPORT=\ \ "Q_DECLARE_FLAGS(Flags, Enum)=typedef QFlags Flags; " \ Q_WS_WIN=1 \ Q_WS_MAC=1 \ Q_WS_X11=1 EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES MSCGEN_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO ukui-interface/src/log4qt/ukui-log4qt.cpp0000664000175000017500000000346715167726076017340 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see #if QT_VERSION < 0x060000 #include #else #include #endif #include "ukui-logconfigurator.h" // 初始化ukui-log4qt库,传入application名称 int initUkuiLog4qt(QString strAppName) { if (strAppName.isEmpty()) { return -1; } // 检查纠正名称格式 小写+'-'+数字 strAppName = strAppName.toLower(); #if QT_VERSION < 0x060000 // 非数字和小写字母以'-'代替 strAppName.replace(QRegExp("[^a-z0-9]+"), "-"); // 多个'-'以一个'-'代替 strAppName.replace(QRegExp("[-]+"), "-"); // 去掉头部的非字母串和尾部的'-'' strAppName.replace(QRegExp("(^[^a-z]+|-$)"), ""); #else // 非数字和小写字母以'-'代替 strAppName.replace(QRegularExpression("[^a-z0-9]+"), "-"); // 多个'-'以一个'-'代替 strAppName.replace(QRegularExpression("[-]+"), "-"); // 去掉头部的非字母串和尾部的'-'' strAppName.replace(QRegularExpression("(^[^a-z]+|-$)"), ""); #endif // 初始化log4qt配置 return UkuiLog4qtConfig::instance().init(strAppName); } ukui-interface/src/log4qt/ukui-logrolling.h0000664000175000017500000000603615167726076017736 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see #include #include #include #include /** * @brief UKUI日志文件滚动清理线程类 */ class UkuiLog4qtRolling : public QThread { public: /** * @brief 构造函数 * @param strBaseFilePath 基础日志文件路径 * @param parent 父对象指针 */ UkuiLog4qtRolling(QString strBaseFilePath, QObject *parent = nullptr); /** * @brief 析构函数 */ virtual ~UkuiLog4qtRolling(); /** * @brief 停止线程 */ void stop(); /** * @brief 设置文件检查限制条件 * @param fileInfoList 要检查的文件信息列表 * @param uMaxFileCount 最大允许的文件数量(0表示不限制) * @param uMaxFileSize 最大允许的文件总大小(0表示不限制) */ void setFileCheckLimit(const QFileInfoList &fileInfoList, unsigned uMaxFileCount = 0, quint64 uMaxFileSize = 0); /** * @brief 检查文件数量 * @param fileInfoList 要检查的文件信息列表 */ void checkLogFilesCount(const QFileInfoList &fileInfoList); /** * @brief 检查文件大小 * @param fileInfoList 要检查的文件信息列表 */ void checkLogFilesSize(const QFileInfoList &fileInfoList); public Q_SLOTS: /** * @brief 滚动处理槽函数 */ void onRollingProc(); protected: /** * @brief 线程运行函数 */ void run(); private: /** * @brief 线程退出标志 */ QAtomicInt m_isExit = 1; /** * @brief 当前基础文件路径 */ QString m_strBaseFilePath; /** * @brief 最大文件数限制 * * 允许保留的最大日志文件数量。 * 0表示不限制文件数量。 */ unsigned m_uMaxFileCount = 0; /** * @brief 最大文件大小限制 * * 允许保留的最大日志文件总大小(字节)。 * 0表示不限制文件大小。 */ quint64 m_uMaxFileSize = 0; /** * @brief 文件信息列表 */ QFileInfoList m_listFileInfo; /** * @brief 互斥锁 */ QMutex m_mutex; /** * @brief 条件变量 */ QWaitCondition m_condition; }; #endif // __UKUILOG4QT_ROLLING_H__ ukui-interface/src/log4qt/doc/0000775000175000017500000000000015167726064015177 5ustar fengfengukui-interface/src/log4qt/doc/default.css0000664000175000017500000000132015167726064017331 0ustar fengfengBODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { font-family: Geneva, Arial, Helvetica, sans-serif; } BODY,TD { font-size: 90%; } H1 { text-align: center; font-size: 160%; } H2 { font-size: 120%; } H3 { font-size: 100%; } H2 { background-color: #e8eef2; color: #1a419d; font-weight: bold; padding-right : 10px; padding-top : 2px; padding-left : 10px; padding-bottom : 2px; margin-left : 0px; margin-right : 0px; margin-top : 2px; margin-bottom : 2px; border: 1px solid #cccccc; } A { text-decoration: none; font-weight: bold; color: #1A419D; } A:visited { text-decoration: none; font-weight: bold; color: #1A419D } A:hover { text-decoration: none; background-color: #ddddff; } ukui-interface/src/log4qt/doc/index.html0000664000175000017500000001272015167726064017176 0ustar fengfeng Log4Qt

Log4Qt

Introduction

Log4Qt is a C++ port of the Apache Software Foundation Log4j package using the Trolltech Qt Framework. It is intended to be used by open source and commercial Qt projects.

Documentation

The documentation describes classes and methods that have been added or changed compared to Log4j. The documentation was generated from the source code using Doxygen. It can be accessed here.

How to use

To use Log4Qt within your software project include the Log4Qt source into your project

  1. Download the package from the SourceForge project page
  2. Unpack the Log4Qt package
  3. Add the log4qt source to the Qt project file by adding the following line
    include(<unpackdir>/src/log4qt/log4qt.pri)
  4. Include the Logger class, a layout and an appender class to configure Log4Qt to generate output. The example uses the ConsoleAppender with a TTCCLayout
    include "log4qt/consoleappender.h"
    include "log4qt/logger.h"
    include "log4qt/ttcclayout.h"
  5. Configure a logger to generate output. The example uses the root logger
    // Create a layout
    Log4Qt::LogManager::rootLogger();
    TTCCLayout *p_layout = new TTCCLayout();
    p_layout->setName(QLatin1String("My Layout"));
    p_layout->activateOptions();
    // Create an appender
    ConsoleAppender *p_appender = new ConsoleAppender(p_layout, ConsoleAppender::STDOUT_TARGET);
    p_appender->setName(QLatin1String("My Appender"));
    p_appender->activateOptions();
    // Set appender on root logger
    Log4Qt::Logger::rootLogger()->setAppender(p_appender);
  6. Request a logger by either calling Log4Qt::Logger::logger or using LOG4QT_DECLARE_QCLASS_LOGGER
    // Request a logger and output "Hello World!"
    Log4Qt::Logger::logger(QLatin1String("My Logger"))->info("Hello World!");

Releases

  • 0.3 - 01 March 2009
    Bug fixes, compatibility with VS 2008 and Qt 4.5 RC1
    • Fixed a problem where the pParent parameter of the constructor was not passed on to the QObject constructor (logobject.h)
    • Fixed a problem were OptionConverter::toBoolean would not return the default value, if the conversion fails (optionconverter.cpp)
    • Fixed a compile error on VS 2008 by using Q_UNUSED(&rEvent) instead of Q_UNUSED(rEvent) (varia/denyallfilter.h.h)
    • Fixed VS 2008 unreferenced formal parameter warning by using Q_UNUSED (logmanager.cpp, mdc.cpp, ndc.cpp, propertyconfigurator.cpp, helpers/initialisationhelper.cpp, helpers/patternformatter.cpp)
  • 0.2 - 30 January 2009
    Bug fixes and compatibility with Qt 4.4
    • Added a compile time version check for the Qt version (log4qt.h)
    • Replaced usage of q_atomic_increment and q_atomic_decrement with QAtomicInt for compilation with Qt 4.4 (helpers/logobject.h)
    • Replaced usage of q_atomic_test_and_set_ptr with QAtomicPointer for compilation with Qt 4.4 (logger.h, helpers/classlogger.cpp, helpers/classlogger.h, helpers/initialisationhelper.h)
    • Fixed a problem with Qt 4.4 where QReadWriteLock is by default non-recursive (hierarchy.cpp, logger.cpp)
    • Resolved compilation problem with Microsoft Visual Studio 2005 (logmanager.cpp, helpers/datetime.cpp)
  • 0.1 - 29 December 2007
    Initial Version

Known Problems

  • The Eclipse CDT console does not display the log output of a correctly when using a ConsoleAppender with a TTCCLayout and relative time format. The millisecond count is stripped from the output.

License

Log4Qt is licensed under the Apache License Version 2.0.

Log4Qt requires the Qt framework that is available under several licensing options (Qt licensing). The package is intended to be used under the Nokia Corporation Qt GPL Exception.

Links


SourceForge.net Logo XX February 2009, Martin Heinrich

ukui-interface/src/log4qt/org.ukui.log4qt-test.gschema.xml0000664000175000017500000000324015167726064022512 0ustar fengfeng "true" hook qt messages Control if hook qt messages "DEBUG,console,daily" config rootLogger's level and appenders config rootLogger's level and appenders:"level,appender" ".yyyy-MM-dd" daily log file pattern set daily log file pattern format:one day "%d{yyyy-MM-dd HH:mm:ss,zzz}(%-4r)[%t]|%-5p| - %m%n" set log message's format set log message's format 3600 set check log files delay time set check log files delay time 3 set log files count set log files count,unit s 512 set log files total size set log files total size, unit M ukui-interface/src/log4qt/ukui-log4qt.pri0000664000175000017500000000227615167726076017345 0ustar fengfengDEFINES += LIBUKUILOG4QT_LIBRARY UKUILOG4QT_EXTRA_ENABLE # Qt6 requires C++17 or higher greaterThan(QT_MAJOR_VERSION, 5) { CONFIG += link_pkg_config c++17 PKGCONFIG += gsettings-qt6 } else { config += link_pkg_config c++14 PKGCONFIG += gsettings-qt } # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 #log4qt include($$PWD/log4qt/log4qt.pri) SOURCES += \ $$PWD/ukui-logconfigurator.cpp \ $$PWD/ukui-logrolling.cpp \ $$PWD/ukui-log4qt.cpp HEADERS += \ $$PWD/ukui-logmacros.h \ $$PWD/ukui-logconfigurator.h \ $$PWD/ukui-logrolling.h \ $$PWD/ukui-log4qt.h DISTFILES += \ $$PWD/log4qt.conf ukui-interface/src/log4qt/log4qt.conf0000664000175000017500000000735715167726064016527 0ustar fengfeng#设置储存log文件的根目录 logpath=. #全局设置 #是否重置所有配置,恢复全局设置默认值 log4j.reset=true #设置Log4Qt记录器输入级别 log4j.Debug=INFO #日志记录器存储库的阈值 log4j.threshold=NULL #设置是否监听QDebug输出的字符串 log4j.handleQtMessages=true #设置根Logger的输出log等级为INFO #设置Log输出的几种输出源(appender):console, daily log4j.rootLogger=DEBUG,console,daily #设置终端打印记录器 #记录器类别 --控制台输出 log4j.appender.console=org.apache.log4j.ConsoleAppender #记录器输出目标 log4j.appender.console.target=STDOUT_TARGET #记录器输出布局 (包含日志产生的时间、线程、类别等信息) log4j.appender.console.layout=org.apache.log4j.TTCCLayout #记录器布局日期格式 (年-月-日 时:分:秒.毫秒) log4j.appender.console.layout.dateFormat=yyy-MM-dd hh:mm:ss.zzz #记录器布局包含上下文 log4j.appender.console.layout.contextPrinting=false #记录器布局包含线程信息 #log4j.appender.console.layout.ThreadPrinting=false #设置一个每日储存一个log文件的记录器 #记录器类别 --一天一个文件输出 log4j.appender.daily=org.apache.log4j.DailyRollingFileAppender #记录器输出文件路径 log4j.appender.daily.file=${logpath}/log4qt.log #记录器追加文件内容 log4j.appender.daily.appendFile=true #记录器是否直接写入文件 #log4j.appender.daily.immediateFlush=true #记录器文件名日期后缀 按天 log4j.appender.daily.datePattern=.yyyy-MM-dd #记录器布局分隔符 (根据patten符号格式化输出数据,类似printf的格式化方式) log4j.appender.daily.layout=org.apache.log4j.PatternLayout log4j.appender.daily.layout.conversionPattern=%-5p|%d{yyyy-MM-dd HH:mm:ss,zzz}(%-4r)|%m%n #记录器输出格式 #日志信息格式中几个符号所代表的含义: # -X号: X信息输出时左对齐; # %p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL, # %d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921 # %r: 输出自应用启动到输出该log信息耗费的毫秒数 # %c: 输出日志信息所属的类目,通常就是所在类的全名 (无效) # %t: 输出产生该日志事件的线程名 (无效) # %l: 输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程,以及在代码中的行数(无效)。举例:Testlog4.main (TestLog4.java:10) # %x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。 # %%: 输出一个"%"字符 # %F: 输出日志消息产生时所在的文件名称(无效) # %L: 输出代码中的行号(无效) # %m: 输出代码中指定的消息,产生的日志具体信息(默认在消息内容前追加了文件名,行号,函数名) # %n: 输出一个回车换行符,Windows平台为"\r\n",Unix平台为"\n"输出日志信息换行 # 可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如: # 1) c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,默认的情况下右对齐。 # 2)%-20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,"-"号指定左对齐。 # 3)%.30c:指定输出category的名称,最大的宽度是30,如果category的名称大于30的话,就会将左边多出的字符截掉,但小于30的话也不会有空格。 # 4) .30c:如果category的名称小于20就补空格,并且右对齐,如果其名称长于30字符,就从左边较远输出的字符截掉。 ukui-interface/src/log4qt/ukui-log4qt.h0000664000175000017500000000260115167726064016767 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see //输出debug级别日志 #define KyDebug QMessageLogger(__FILE__, __LINE__, __FUNCTION__).debug //输出info级别日志 #define KyInfo QMessageLogger(__FILE__, __LINE__, __FUNCTION__).info //输出warning级别日志 #define KyWarning QMessageLogger(__FILE__, __LINE__, __FUNCTION__).warning //输出critical级别日志 #define KyCritical QMessageLogger(__FILE__, __LINE__, __FUNCTION__).critical //输出fatal级别日志 #define KyFatal QMessageLogger(__FILE__, __LINE__, __FUNCTION__).fatal // 初始化ukui-log4qt库,传入application名称 int initUkuiLog4qt(QString strAppName); #endif // __UKUILOG4QT_H__ ukui-interface/src/log4qt/ukui-log4qt.pro0000664000175000017500000000274115167726076017350 0ustar fengfengQT -= gui TEMPLATE = lib DEFINES += LIBUKUILOG4QT_LIBRARY UKUILOG4QT_EXTRA_ENABLE CONFIG += link_pkgconfig \ c++11 # Qt6 requires C++17 or higher greaterThan(QT_MAJOR_VERSION, 5) { CONFIG += c++17 PKGCONFIG += gsettings-qt6 } else { PKGCONFIG += gsettings-qt } # The following define makes your compiler emit warnings if you use # any Qt feature that has been marked deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 #log4qt include($$PWD/log4qt/log4qt.pri) SOURCES += \ ukui-logconfigurator.cpp \ ukui-logrolling.cpp \ ukui-log4qt.cpp HEADERS += \ ukui-logmacros.h \ ukui-logconfigurator.h \ ukui-logrolling.h \ ukui-log4qt.h # Default rules for deployment. unix { target.path = /usr/lib } !isEmpty(target.path): INSTALLS += target schemes.files += org.ukui.log4qt.gschema.xml schemes.path = /usr/share/glib-2.0/schemas/ headers_main.path = /usr/include headers_main.files += ukui-log4qt.h INSTALLS += schemes \ headers_main DISTFILES += \ log4qt.conf ukui-interface/src/log4qt/README.txt0000664000175000017500000000005315167726064016126 0ustar fengfengSee HTML documentation under doc/index.htmlukui-interface/src/log4qt/ukui-logmacros.h0000664000175000017500000000477115167726064017555 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see #if defined(LIBUKUILOG4QT_LIBRARY) # define LIBUKUILOG4QT_EXPORT Q_DECL_EXPORT #else # define LIBUKUILOG4QT_EXPORT Q_DECL_IMPORT #endif // 日志文件相对home目录路径 #define UKUILOG4QT_ROOTPATH "/.log/" // gsettings相关相关属性 #define UKUILOG4QT_SETTINGS "org.ukui.ukui-log4qt" #define UKUILOG4QT_SETTINGS_RESET "log4jReset" #define UKUILOG4QT_SETTINGS_DEBUG "log4jDebug" #define UKUILOG4QT_SETTINGS_HANDLEQT "log4jHandleqtmessages" #define UKUILOG4QT_SETTINGS_ROOTLOGGER "log4jRootlogger" #define UKUILOG4QT_SETTINGS_DAILY_DATEPATTERN "log4jAppenderDailyDatepattern" #define UKUILOG4QT_SETTINGS_DAILY_CONVERSIONPATTERN "log4jAppenderDailyLayoutConversionpattern" #define UKUILOG4QT_SETTINGS_ROLLINGCHECK_DELAYTIME "delaytime" #define UKUILOG4QT_SETTINGS_ROLLINGCHECK_MAXFILECOUNT "maxfilecount" #define UKUILOG4QT_SETTINGS_ROLLINGCHECK_MAXFILESIZE "maxfilesize" // log4qt相关属性 #define UKUILOG4QT_RESET "log4j.reset" //是否重置所有配置,恢复全局设置默认值 #define UKUILOG4QT_DEBUG "log4j.Debug" //设置日志sdk内部记录器级别 #define UKUILOG4QT_HANDLEQT "log4j.handleQtMessages" //设置是否监听QDebug输出的字符串 #define UKUILOG4QT_ROOTLOGGER "log4j.rootLogger" //设置根Logger的输出log等级和输出目的地 #define UKUILOG4QT_DAILY_DATEPATTERN "log4j.appender.daily.datePattern" //记录器文件名日期后缀 按天 #define UKUILOG4QT_DAILY_CONVERSIONPATTERN "log4j.appender.daily.layout.conversionPattern" //记录器日志输出格式 #endif // __UKUI_LOGMACROS__ ukui-interface/src/log4qt/LICENSE-2.0.txt0000664000175000017500000002613615167726064016562 0ustar fengfeng Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ukui-interface/src/log4qt/org.ukui.log4qt.gschema.xml0000664000175000017500000000403115167726064021534 0ustar fengfeng "true" reset all log4j config Control if reset all log4j config "INFO" config logLogger's output level config logLogger's output level: DEBUG/INFO/WARN/ERROR "true" hook qt messages Control if hook qt messages "INFO,daily" config rootLogger's level and appenders config rootLogger's level and appenders:"level,appender" ".yyyy-MM-dd" daily log file pattern set daily log file pattern format:one day "%d{yyyy-MM-dd HH:mm:ss,zzz}(%-4r)[%t]|%-5p| - %m%n" set log message's format set log message's format 3600 set check log files delay time set check log files delay time 3 set log files count set log files count,unit s 512 set log files total size set log files total size, unit M ukui-interface/src/log4qt/ukui-logrolling.cpp0000664000175000017500000001515215167726076020270 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see #include #include #include /** * @brief 构造函数 * @param strBaseFilePath 基础日志文件路径 * @param parent 父对象指针 */ UkuiLog4qtRolling::UkuiLog4qtRolling(QString strBaseFilePath, QObject *parent) : QThread(parent), m_isExit(0), m_strBaseFilePath(strBaseFilePath) { } /** * @brief 析构函数 */ UkuiLog4qtRolling::~UkuiLog4qtRolling() {} /** * @brief 线程运行函数 */ void UkuiLog4qtRolling::run() { // 检查退出标志,如果已设置则直接返回 if (m_isExit.loadAcquire()) { return; } // 主循环:等待任务并执行清理操作 while (!m_isExit.loadAcquire()) { QMutexLocker locker(&m_mutex); // 等待条件变量唤醒(有新的清理任务) m_condition.wait(&m_mutex); // 再次检查退出标志,如果已设置则退出循环 if (m_isExit.loadAcquire()) { break; } // 执行文件数量检查(如果设置了限制) if (m_uMaxFileCount > 0) { checkLogFilesCount(m_listFileInfo); } // 执行文件大小检查(如果设置了限制) if (m_uMaxFileSize > 0) { checkLogFilesSize(m_listFileInfo); } } } /** * @brief 设置文件检查限制条件 * @param fileInfoList 要检查的文件信息列表 * @param uMaxFileCount 最大允许的文件数量(0表示不限制) * @param uMaxFileSize 最大允许的文件总大小(0表示不限制) */ void UkuiLog4qtRolling::setFileCheckLimit( const QFileInfoList &fileInfoList, unsigned uMaxFileCount, quint64 uMaxFileSize) { QMutexLocker locker(&m_mutex); // 更新文件信息列表和限制条件 m_listFileInfo = fileInfoList; m_uMaxFileCount = uMaxFileCount; m_uMaxFileSize = uMaxFileSize; // 唤醒等待的线程开始执行清理任务 m_condition.wakeOne(); } /** * @brief 停止线程 */ void UkuiLog4qtRolling::stop() { // 设置退出标志 m_isExit = 1; // 获取互斥锁并唤醒等待的线程 QMutexLocker locker(&m_mutex); m_condition.wakeOne(); } /** * @brief 检查文件数量 * @param fileInfoList 要检查的文件信息列表 */ void UkuiLog4qtRolling::checkLogFilesCount(const QFileInfoList &fileInfoList) { // 检查退出标志,如果已设置则直接返回 if (m_isExit.loadAcquire()) { return; } // 检查文件数量是否超过限制 if (fileInfoList.size() <= (int)(m_uMaxFileCount)) { return; } // 计算需要删除的文件数量 int filesToRemove = fileInfoList.size() - m_uMaxFileCount; QTime startTime = QTime::currentTime(); // 从文件列表末尾开始删除(最旧的文件在前) for (int i = fileInfoList.size() - 1; i >= 0 && filesToRemove > 0; i--) { // 检查超时或退出标志,避免长时间阻塞 if (startTime.msecsTo(QTime::currentTime()) > 500 || m_isExit.loadAcquire()) { break; } QString filePath = fileInfoList[i].absoluteFilePath(); // 跳过当前正在使用的基础文件,避免删除正在写入的文件 if (filePath == m_strBaseFilePath) { continue; } // 尝试删除文件 QFile file(filePath); if (file.remove()) { KyDebug() << QString("Removed old log file: %1").arg(filePath); filesToRemove--; } else { KyWarning() << "Failed to remove old log file:" << filePath; } } } /** * @brief 检查文件大小 * @param fileInfoList 要检查的文件信息列表 */ void UkuiLog4qtRolling::checkLogFilesSize(const QFileInfoList &fileInfoList) { // 检查退出标志,如果已设置则直接返回 if (m_isExit.loadAcquire()) { return; } // 计算所有文件的总大小 qint64 totalSize = 0; QTime startTime = QTime::currentTime(); // 遍历所有文件,累加文件大小 for (const QFileInfo &fileInfo : fileInfoList) { // 设置200ms超时,避免大小计算耗时过长 if (startTime.msecsTo(QTime::currentTime()) > 200) { qWarning("Size calculation timeout, using estimated size"); break; } totalSize += fileInfo.size(); } // 检查总大小是否超过限制 if (totalSize <= (qint64)(m_uMaxFileSize)) { return; } // 计算需要清理的大小 qint64 sizeToRemove = totalSize - m_uMaxFileSize; QString currentFilePath = m_strBaseFilePath; startTime = QTime::currentTime(); // 从文件列表末尾开始清理(最旧的文件在前) for (int i = fileInfoList.size() - 1; i >= 0 && sizeToRemove > 0; i--) { // 设置1秒超时,避免清理过程耗时过长 if (startTime.msecsTo(QTime::currentTime()) > 1000 || m_isExit.loadAcquire()) { qWarning() << "Size cleanup timeout, stopping to avoid blocking"; break; } QString filePath = fileInfoList[i].absoluteFilePath(); qint64 fileSize = fileInfoList[i].size(); // 处理当前正在使用的文件 if (filePath == currentFilePath) { // 对于当前文件,清空内容而不是删除,避免影响正在进行的日志记录 QProcess process; process.start("sh", QStringList() << "-c" << QString("> %1").arg(filePath)); process.waitForFinished(100); sizeToRemove -= fileSize; } else { // 对于历史文件,直接删除 QFile file(filePath); if (file.remove()) { KyDebug() << QString("Removed old log file: %1 (size: %2 bytes)").arg(filePath).arg(fileSize); sizeToRemove -= fileSize; } else { qWarning() << QString("Failed to remove old log file: %1").arg(filePath); } } } } ukui-interface/src/log4qt/log4qt/0000775000175000017500000000000015167726076015647 5ustar fengfengukui-interface/src/log4qt/log4qt/level.h0000664000175000017500000001346115167726064017131 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: level.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_LEVEL_H #define LOG4QT_LEVEL_H /****************************************************************************** * Dependencies ******************************************************************************/ #include #include #include "log4qt/log4qt.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * \brief The class Level defines the level of a logging event. * * \note All the functions declared in this class are thread-safe. */ class LIBUKUILOG4QT_EXPORT Level { public: // Comparisson operators rely on the order: // NULL_INT < ALL_INT < TRACE_INT < ... // Serialisation uses unsigned 8 bit int /*! * The enumeration Value contains all possible Level values. */ enum Value { /*! NULL_INT is used for no level has been specified */ NULL_INT = 0, ALL_INT = 32, TRACE_INT = 64, DEBUG_INT = 96, INFO_INT = 128, WARN_INT = 150, ERROR_INT = 182, FATAL_INT = 214, OFF_INT = 255 }; public: Level(Value value = NULL_INT); // Level(const Level &rOther); // Use compiler default // virtual ~Level(); // Use compiler default // Level &operator=(const Level &rOther); // Use compiler default int syslogEquivalent() const; int toInt() const; bool operator==(const Level &rOther) const; bool operator!=(const Level &rOther) const; bool operator<(const Level &rOther) const; bool operator<=(const Level &rOther) const; bool operator>(const Level &rOther) const; bool operator>=(const Level &rOther) const; QString toString() const; static Level fromString(const QString &rName, bool *pOk = 0); private: // QMutex mObjectGuard; volatile Value mValue; #ifndef QT_NO_DATASTREAM // Needs to be friend to stream objects friend QDataStream &operator<<(QDataStream &rStream, const Level &rLevel); friend QDataStream &operator>>(QDataStream &rStream, Level &rLevel); #endif // QT_NO_DATASTREAM }; /************************************************************************** * Operators, Helper **************************************************************************/ #ifndef QT_NO_DATASTREAM /*! * \relates Level * * Writes the given error \a rLevel to the given stream \a rStream, * and returns a reference to the stream. */ QDataStream &operator<<(QDataStream &rStream, const Level &rLevel); /*! * \relates Level * * Reads an error from the given stream \a rStream into the given * error \a rLevel, and returns a reference to the stream. */ QDataStream &operator>>(QDataStream &rStream, Level &rLevel); #endif // QT_NO_DATASTREAM #ifndef QT_NO_DEBUG_STREAM /*! * \relates Level * * Writes all object member variables to the given debug stream \a rDebug * and returns the stream. * * * %Level("ERROR") * * \sa QDebug */ QDebug operator<<(QDebug debug, const Level &rLevel); #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Inline **************************************************************************/ inline Level::Level(Value value) : mValue(value) {} inline int Level::toInt() const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe return mValue; } inline bool Level::operator==(const Level &rOther) const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe return mValue == rOther.mValue; } inline bool Level::operator!=(const Level &rOther) const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe return mValue != rOther.mValue; } inline bool Level::operator<(const Level &rOther) const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe return mValue < rOther.mValue; } inline bool Level::operator<=(const Level &rOther) const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe return mValue <= rOther.mValue; } inline bool Level::operator>(const Level &rOther) const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe return mValue > rOther.mValue; } inline bool Level::operator>=(const Level &rOther) const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe return mValue >= rOther.mValue; } } // namespace Log4Qt Q_DECLARE_METATYPE(Log4Qt::Level) Q_DECLARE_TYPEINFO(Log4Qt::Level, Q_MOVABLE_TYPE); #endif // LOG4QT_LEVEL_H ukui-interface/src/log4qt/log4qt/simplelayout.h0000664000175000017500000000574515167726064020557 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: simplelayout.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_SIMPLELAYOUT_H #define LOG4QT_SIMPLELAYOUT_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/layout.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * \brief The class SimpleLayout outputs the level and message of a logging * event. * * \note The ownership and lifetime of objects of this class are managed. * See \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT SimpleLayout : public Layout { Q_OBJECT public: SimpleLayout(QObject *pParent = 0); // virtual ~SimpleLayout(); // Use compiler default private: SimpleLayout(const SimpleLayout &rOther); // Not implemented SimpleLayout &operator=(const SimpleLayout &rOther); // Not implemented public: virtual QString format(const LoggingEvent &rEvent); protected: #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream * \a rDebug and returns the stream. * * * %SimpleLayout(name:"SL" referencecount:1) * * \sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const; #endif // QT_NO_DEBUG_STREAM }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline SimpleLayout::SimpleLayout(QObject *pParent) : Layout(pParent) {} } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::SimpleLayout, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_SIMPLELAYOUT_H ukui-interface/src/log4qt/log4qt/spi/0000775000175000017500000000000015167726076016442 5ustar fengfengukui-interface/src/log4qt/log4qt/spi/filter.h0000664000175000017500000000663315167726076020110 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: filter.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_FILTER_H #define LOG4QT_FILTER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/helpers/logobject.h" #include "log4qt/helpers/logobjectptr.h" #include "log4qt/log4qt.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { class LoggingEvent; /*! * \brief The class Filter is the base class for all filters. * * \note The ownership and lifetime of objects of this class are managed. * See \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT Filter : public LogObject { Q_OBJECT /*! * The property holds the next filter of this filter. * * The default is 0 for no next filter. * * \sa next(), setNext() */ Q_PROPERTY(Filter* next READ next WRITE setNext) public: enum Decision { ACCEPT, DENY, NEUTRAL }; Q_ENUMS(Decision); public: Filter(QObject *pObject = 0); // Filter(const Filter &rOther); // Use compiler default virtual ~Filter(); // Filter &operator=(const Filter &rOther); // Use compiler default Filter* next() const; void setNext(Filter *pFilter); virtual void activateOptions(); virtual Decision decide(const LoggingEvent &rEvent) const = 0; private: LogObjectPtr mpNext; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline Filter::Filter(QObject *pObject) : LogObject(pObject), mpNext(0) {} inline Filter::~Filter() {} inline Filter* Filter::next() const { return mpNext; } inline void Filter::activateOptions() {} } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::Filter, Q_COMPLEX_TYPE); // Use default #if QT_VERSION < 0x060000 Q_DECLARE_TYPEINFO(Log4Qt::LogObjectPtr, Q_MOVABLE_TYPE); #else Q_DECLARE_TYPEINFO(Log4Qt::LogObjectPtr, Q_COMPLEX_TYPE); #endif // Qt6 compatibility: opaque pointer declared in appender.h #endif // LOG4QT_FILTER_H ukui-interface/src/log4qt/log4qt/spi/filter.cpp0000664000175000017500000000370715167726064020437 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: filter.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/spi/filter.h" #include namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: Filter **************************************************************************/ void Filter::setNext(Filter *pFilter) { mpNext = pFilter; } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/patternlayout.cpp0000664000175000017500000000752715167726064021276 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: patternlayout.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/patternlayout.h" #include #include "log4qt/helpers/patternformatter.h" #include "log4qt/loggingevent.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: PatternLayout **************************************************************************/ PatternLayout::PatternLayout(QObject *pParent) : Layout(pParent), mPattern(), mpPatternFormatter(0) { setConversionPattern(DEFAULT_CONVERSION_PATTERN); } PatternLayout::PatternLayout(const QString &rPattern, QObject *pParent) : Layout(pParent), mPattern(), mpPatternFormatter(0) { setConversionPattern(rPattern); } PatternLayout::PatternLayout(ConversionPattern conversionPattern, QObject *pParent) : Layout(pParent), mPattern(), mpPatternFormatter(0) { setConversionPattern(conversionPattern); } PatternLayout::~PatternLayout() { delete mpPatternFormatter; } void PatternLayout::setConversionPattern(ConversionPattern conversionPattern) { switch (conversionPattern) { case DEFAULT_CONVERSION_PATTERN: setConversionPattern(QLatin1String("%m%n")); break; case TTCC_CONVERSION_PATTERN: setConversionPattern(QLatin1String("%r [%t] %p %c %x - %m%n")); break; default: Q_ASSERT_X(false, "PatternLayout::setConversionFormat", "Unkown ConversionFormat"); setConversionPattern(QString()); } } QString PatternLayout::format(const LoggingEvent &rEvent) { Q_ASSERT_X(mpPatternFormatter, "PatternLayout::format()", "mpPatternConverter must not be null"); return mpPatternFormatter->format(rEvent); } void PatternLayout::updatePatternFormatter() { delete mpPatternFormatter; mpPatternFormatter = new PatternFormatter(mPattern); } #ifndef QT_NO_DEBUG_STREAM QDebug PatternLayout::debug(QDebug &rDebug) const { rDebug.nospace() << "PatternLayout(" << "name:" << name() << " " << "pattern:" << conversionPattern() << " " << "referencecount:" << referenceCount() << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/loggingevent.cpp0000664000175000017500000001707615167726064021053 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: loggingevent.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *****************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/loggingevent.h" #include #include #include #include #include #include #include "log4qt/helpers/datetime.h" #include "log4qt/helpers/initialisationhelper.h" #include "log4qt/logger.h" #include "log4qt/mdc.h" #include "log4qt/ndc.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ LOG4QT_GLOBAL_STATIC(QMutex, sequence_guard) /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: LoggingEvent **************************************************************************/ LoggingEvent::LoggingEvent() : QEvent(eventId), mLevel(Level::NULL_INT), mpLogger(0), mMessage(), mNdc(NDC::peek()), mProperties(MDC::context()), mSequenceNumber(nextSequenceNumber()), mThreadName(), mTimeStamp(DateTime::currentDateTime().toMilliSeconds()) { setThreadNameToCurrent(); } LoggingEvent::LoggingEvent(const Logger *pLogger, Level level, const QString &rMessage) : QEvent(eventId), mLevel(level), mpLogger(pLogger), mMessage(rMessage), mNdc(NDC::peek()), mProperties(MDC::context()), mSequenceNumber(nextSequenceNumber()), mThreadName(), mTimeStamp(DateTime::currentDateTime().toMilliSeconds()) { setThreadNameToCurrent(); } LoggingEvent::LoggingEvent(const Logger *pLogger, Level level, const QString &rMessage, qint64 timeStamp) : QEvent(eventId), mLevel(level), mpLogger(pLogger), mMessage(rMessage), mNdc(NDC::peek()), mProperties(MDC::context()), mSequenceNumber(nextSequenceNumber()), mThreadName(), mTimeStamp(timeStamp) { setThreadNameToCurrent(); } LoggingEvent::LoggingEvent(const Logger *pLogger, Level level, const QString &rMessage, const QString &rNdc, const QHash &rProperties, const QString &rThreadName, qint64 timeStamp) : QEvent(eventId), mLevel(level), mpLogger(pLogger), mMessage(rMessage), mNdc(rNdc), mProperties(rProperties), mSequenceNumber(nextSequenceNumber()), mThreadName(rThreadName), mTimeStamp(timeStamp) { } QString LoggingEvent::loggerName() const { if (mpLogger) return mpLogger->name(); else return QString(); } QString LoggingEvent::toString() const { return level().toString() + QLatin1Char(':') + message(); } qint64 LoggingEvent::sequenceCount() { QMutexLocker locker(sequence_guard()); return msSequenceCount; } qint64 LoggingEvent::startTime() { return InitialisationHelper::startTime(); } void LoggingEvent::setThreadNameToCurrent() { if (QThread::currentThread()) { mThreadName = QThread::currentThread()->objectName(); if (mThreadName.isEmpty()) { mThreadName = QString("%1").arg((quint64)QThread::currentThreadId()); } } } qint64 LoggingEvent::nextSequenceNumber() { QMutexLocker locker(sequence_guard()); return ++msSequenceCount; } qint64 LoggingEvent::msSequenceCount = 0; const QEvent::Type LoggingEvent::eventId = static_cast(QEvent::registerEventType()); /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DATASTREAM QDataStream &operator<<(QDataStream &rStream, const LoggingEvent &rLoggingEvent) { QBuffer buffer; buffer.open(QIODevice::WriteOnly); QDataStream stream(&buffer); // version quint16 version = 0; stream << version; // version 0 data stream << rLoggingEvent.mLevel << rLoggingEvent.loggerName() << rLoggingEvent.mMessage << rLoggingEvent.mNdc << rLoggingEvent.mProperties << rLoggingEvent.mSequenceNumber << rLoggingEvent.mThreadName << rLoggingEvent.mTimeStamp; buffer.close(); rStream << buffer.buffer(); return rStream; } QDataStream &operator>>(QDataStream &rStream, LoggingEvent &rLoggingEvent) { QByteArray array; rStream >> array; QBuffer buffer(&array); buffer.open(QIODevice::ReadOnly); QDataStream stream(&buffer); // version quint16 version; stream >> version; // Version 0 data QString logger; stream >> rLoggingEvent.mLevel >> logger >> rLoggingEvent.mMessage >> rLoggingEvent.mNdc >> rLoggingEvent.mProperties >> rLoggingEvent.mSequenceNumber >> rLoggingEvent.mThreadName >> rLoggingEvent.mTimeStamp; if (logger.isEmpty()) rLoggingEvent.mpLogger = 0; else rLoggingEvent.mpLogger = Logger::logger(logger); buffer.close(); return rStream; } #endif // QT_NO_DATASTREAM #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const LoggingEvent &rLoggingEvent) { QString logger; if (rLoggingEvent.logger() != 0) logger = rLoggingEvent.logger()->name(); debug.nospace() << "LoggingEvent(" << "level:" << rLoggingEvent.level().toString() << " " << "logger:" << logger << " " << "message:" << rLoggingEvent.message() << " " << "sequencenumber:" << rLoggingEvent.sequenceNumber() << " " << "threadname:" << rLoggingEvent.threadName() << " " << "timestamp:" << rLoggingEvent.timeStamp() << "(" << DateTime::fromMilliSeconds(rLoggingEvent.timeStamp()) << ")" << "sequenceCount:" << rLoggingEvent.sequenceCount() << ")"; return debug.space(); } #endif // QT_NO_DEBUG_STREAM } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/rollingfileappender.h0000664000175000017500000001275215167726064022051 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: rollingfileappender.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_ROLINGFILEAPPENDER_H #define LOG4QT_ROLINGFILEAPPENDER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/fileappender.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * \brief The class RollingFileAppender extends FileAppender to backup * the log files when they reach a certain size. * * \note All the functions declared in this class are thread-safe. * * \note The ownership and lifetime of objects of this class are managed. * See \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT RollingFileAppender : public FileAppender { Q_OBJECT /*! * The property holds the maximum backup count used by the appender. * * The default is 1. * * \sa maxBackupIndex(), setMaxBackupIndex() */ Q_PROPERTY(int maxBackupIndex READ maxBackupIndex WRITE setMaxBackupIndex) /*! * The property holds the maximum file size used by the appender. * * The default is 10 MB (10 * 1024 * 1024). * * \sa maximumFileSize(), setMaximumFileSize() */ Q_PROPERTY(qint64 maximumFileSize READ maximumFileSize WRITE setMaximumFileSize) /*! * The property sets the maximum file size from a string value. * * \sa setMaxFileSize(), maximumFileSize() */ Q_PROPERTY(QString maxFileSize WRITE setMaxFileSize) public: RollingFileAppender(QObject *pParent = 0); RollingFileAppender(Layout *pLayout, const QString &rFileName, QObject *pParent = 0); RollingFileAppender(Layout *pLayout, const QString &rFileName, bool append, QObject *pParent = 0); virtual ~RollingFileAppender(); private: RollingFileAppender(const RollingFileAppender &rOther); // Not implemented RollingFileAppender &operator=(const RollingFileAppender &rOther); // Not implemented public: int maxBackupIndex() const; qint64 maximumFileSize() const; void setMaxBackupIndex(int maxBackupIndex); void setMaximumFileSize(qint64 maximumFileSize); void setMaxFileSize(const QString &rMaxFileSize); protected: virtual void append(const LoggingEvent &rEvent); virtual void asyncAppend(const LoggingEvent &rEvent); #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream * \a rDebug and returns the stream. * * * %RollingFileAppender(name:"RFA" appendfile:false bufferedio:true * encoding:"" file:"/log.txt" filter: 0x0 * immediateflush:true isactive:true * isclosed:false layout:"TTCC" maxbackupindex:2 * maximumfilesize:40 referencecount:1 * threshold:"NULL" writer:0x4175af8) * * \sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const; #endif // QT_NO_DEBUG_STREAM private: void rollOver(); private: int mMaxBackupIndex; qint64 mMaximumFileSize; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline int RollingFileAppender::maxBackupIndex() const { QMutexLocker locker(&mObjectGuard); return mMaxBackupIndex; } inline qint64 RollingFileAppender::maximumFileSize() const { QMutexLocker locker(&mObjectGuard); return mMaximumFileSize; } inline void RollingFileAppender::setMaxBackupIndex(int maxBackupIndex) { QMutexLocker locker(&mObjectGuard); mMaxBackupIndex = maxBackupIndex; } inline void RollingFileAppender::setMaximumFileSize(qint64 maximumFileSize) { QMutexLocker locker(&mObjectGuard); mMaximumFileSize = maximumFileSize; } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::RollingFileAppender, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_ROLINGFILEAPPENDER_H ukui-interface/src/log4qt/log4qt/rollingfileappender.cpp0000664000175000017500000001375515167726076022413 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: rollingfileappender.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/rollingfileappender.h" #include #include #if QT_VERSION < 0x060000 #include #endif #include "log4qt/helpers/optionconverter.h" #include "log4qt/layout.h" #include "log4qt/loggingevent.h" namespace Log4Qt { /************************************************************************ Declarations *************************************************************************/ /************************************************************************ C helper functions *************************************************************************/ /************************************************************************ Class implementation: RollingFileAppender *************************************************************************/ RollingFileAppender::RollingFileAppender(QObject *pParent) : FileAppender(pParent), mMaxBackupIndex(1), mMaximumFileSize(10*1024*1024) { } RollingFileAppender::RollingFileAppender(Layout *pLayout, const QString &rFileName, QObject *pParent) : FileAppender(pLayout, rFileName, pParent), mMaxBackupIndex(1), mMaximumFileSize(10*1024*1024) { } RollingFileAppender::RollingFileAppender(Layout *pLayout, const QString &rFileName, bool append, QObject *pParent) : FileAppender(pLayout, rFileName, append, pParent), mMaxBackupIndex(1), mMaximumFileSize(10*1024*1024) { } RollingFileAppender::~RollingFileAppender() { close(); } void RollingFileAppender::setMaxFileSize(const QString &rMaxFileSize) { bool ok; qint64 max_file_size = OptionConverter::toFileSize(rMaxFileSize, &ok); if (ok) setMaximumFileSize(max_file_size); } void RollingFileAppender::append(const LoggingEvent &rEvent) { // Q_ASSERT_X(, "RollingFileAppender::append()", "Lock must be held by caller") FileAppender::append(rEvent); #ifndef UKUILOG4QT_EXTRA_ENABLE if (writer()->device()->size() > this->mMaximumFileSize) rollOver(); #endif } void RollingFileAppender::asyncAppend(const LoggingEvent &rEvent) { // Q_ASSERT_X(, "RollingFileAppender::asyncAppend()", "Lock must be held by caller") FileAppender::asyncAppend(rEvent); if (writer()->device()->size() > this->mMaximumFileSize) rollOver(); } void RollingFileAppender::rollOver() { // Q_ASSERT_X(, "RollingFileAppender::rollOver()", "Lock must be held by caller") logger()->debug("Rolling over with maxBackupIndex = %1", mMaxBackupIndex); closeFile(); QFile f; f.setFileName(file() + QLatin1Char('.') + QString::number(mMaxBackupIndex)); if (f.exists() && !removeFile(f)) return; QString target_file_name; int i; for (i = mMaxBackupIndex - 1; i >=1; i--) { f.setFileName(file() + QLatin1Char('.') + QString::number(i)); if (f.exists()) { target_file_name = file() + QLatin1Char('.') + QString::number(i + 1); if (!renameFile(f, target_file_name)) return; } } f.setFileName(file()); target_file_name = file() + QLatin1String(".1"); if (!renameFile(f, target_file_name)) return; openFile(); } #ifndef QT_NO_DEBUG_STREAM QDebug RollingFileAppender::debug(QDebug &rDebug) const { QString layout_name; if (layout()) layout_name = layout()->name(); QString codec_name; #if QT_VERSION < 0x060000 if (encoding()) codec_name = QLatin1String(encoding()->name()); #else codec_name = QLatin1String(QStringConverter::nameForEncoding(encoding())); #endif rDebug.nospace() << "RollingFileAppender(" << "name:" << name() << " " << "appendfile:" << appendFile() << " " << "bufferedio:" << bufferedIo() << " " << "encoding:" << codec_name << " " << "file:" << file() << " " << "filter:" << firstFilter() << " " << "immediateflush:" << immediateFlush() << " " << "isactive:" << isActive() << " " << "isclosed:" << isClosed() << " " << "layout:" << layout_name << " " << "maxbackupindex:" << maxBackupIndex() << " " << "maximumfilesize:" << maximumFileSize() << " " << "referencecount:" << referenceCount() << " " << "threshold:" << threshold().toString() << " " << "writer:" << writer() << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/logmanager.cpp0000664000175000017500000004156015167726076020475 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: logmanager.cpp * created: September 2007 * author: Martin Heinrich * * * changes: Sep 2008, Martin Heinrich: * - Resolved compilation problem with Microsoft Visual Studio 2005 * Feb 2009, Martin Heinrich * - Fixed VS 2008 unreferenced formal parameter warning by using * Q_UNUSED in operator<<. * * * Copyright 2007 - 2009 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/logmanager.h" #include #include #include #include #include #include #include "log4qt/consoleappender.h" #include "log4qt/helpers/datetime.h" #include "log4qt/helpers/initialisationhelper.h" #include "log4qt/helpers/optionconverter.h" #include "log4qt/hierarchy.h" #include "log4qt/propertyconfigurator.h" #include "log4qt/ttcclayout.h" #include "log4qt/varia/denyallfilter.h" #include "log4qt/varia/levelrangefilter.h" #include namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ LOG4QT_DECLARE_STATIC_LOGGER(static_logger, Log4Qt::LogManager) LOG4QT_GLOBAL_STATIC(QMutex, singleton_guard) /************************************************************************** * Class implementation: LogManager **************************************************************************/ LogManager::LogManager() : #if QT_VERSION < 0x050E00 mObjectGuard(QMutex::Recursive), // Recursive for doStartup() to call doConfigureLogLogger() #endif mpLoggerRepository(new Hierarchy()), mHandleQtMessages(false), mOldQtMsgHandler(0) { } LogManager::~LogManager() { static_logger()->warn("Unexpected destruction of LogManager"); // doSetConfigureHandleQtMessages(false); // delete mpLoggerRepository; } Logger *LogManager::rootLogger() { return instance()->mpLoggerRepository->rootLogger(); } QList LogManager::loggers() { return instance()->mpLoggerRepository->loggers(); } Level LogManager::threshold() { return instance()->mpLoggerRepository->threshold(); } void LogManager::setThreshold(Level level) { instance()->mpLoggerRepository->setThreshold(level); } bool LogManager::exists(const char *pName) { return instance()->mpLoggerRepository->exists(QLatin1String(pName)); } LogManager *LogManager::instance() { // Do not use LOG4QT_GLOBAL_STATIC. The LogManager is rather expensive // to construct, an exit handler must be set and doStartup must be // called. if (!mspInstance) { QMutexLocker locker(singleton_guard()); if (!mspInstance) { mspInstance = new LogManager; // qAddPostRoutine(shutdown); atexit(shutdown); mspInstance->doConfigureLogLogger(); mspInstance->welcome(); mspInstance->doStartup(); } } return mspInstance; } Logger *LogManager::logger(const QString &rName) { return instance()->mpLoggerRepository->logger(rName); } void LogManager::resetConfiguration() { setHandleQtMessages(false); instance()->mpLoggerRepository->resetConfiguration(); configureLogLogger(); } const char* LogManager::version() { return LOG4QT_VERSION_STR; } void LogManager::shutdown() { instance()->mpLoggerRepository->shutdown(); } void LogManager::doSetHandleQtMessages(bool handleQtMessages) { QMutexLocker locker(&mObjectGuard); if (instance()->mHandleQtMessages == handleQtMessages) return; instance()->mHandleQtMessages = handleQtMessages; if (instance()->mHandleQtMessages) { static_logger()->trace("Activate Qt message handling"); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) instance()->mOldQtMsgHandler = qInstallMsgHandler(qtMessageHandler); #else instance()->mOldQtMsgHandler = qInstallMessageHandler(qtMessageHandler); #endif } else { static_logger()->trace("Deactivate Qt message handling"); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) qInstallMsgHandler(instance()->mOldQtMsgHandler); #else qInstallMessageHandler(instance()->mOldQtMsgHandler); #endif } } void LogManager::doConfigureLogLogger() { QMutexLocker locker(&instance()->mObjectGuard); // Level QString value = InitialisationHelper::setting(QLatin1String("Debug"), QLatin1String("ERROR")); logLogger()->setLevel(OptionConverter::toLevel(value, Level::DEBUG_INT)); // Common layout TTCCLayout *p_layout = new TTCCLayout(); p_layout->setName(QLatin1String("LogLog TTCC")); p_layout->setContextPrinting(false); p_layout->activateOptions(); // Common deny all filter Filter *p_denyall = new DenyAllFilter(); p_denyall->activateOptions(); // ConsoleAppender on stdout for all events <= INFO ConsoleAppender *p_appender; LevelRangeFilter *p_filter; p_appender = new ConsoleAppender(p_layout, ConsoleAppender::STDOUT_TARGET); p_filter = new LevelRangeFilter(); p_filter->setNext(p_denyall); p_filter->setLevelMin(Level::NULL_INT); p_filter->setLevelMax(Level::INFO_INT); p_filter->activateOptions(); p_appender->setName(QLatin1String("LogLog stdout")); p_appender->addFilter(p_filter); p_appender->activateOptions(); logLogger()->addAppender(p_appender); // ConsoleAppender on stderr for all events >= WARN p_appender = new ConsoleAppender(p_layout, ConsoleAppender::STDERR_TARGET); p_filter = new LevelRangeFilter(); p_filter->setNext(p_denyall); p_filter->setLevelMin(Level::WARN_INT); p_filter->setLevelMax(Level::OFF_INT); p_filter->activateOptions(); p_appender->setName(QLatin1String("LogLog stderr")); p_appender->addFilter(p_filter); p_appender->activateOptions(); logLogger()->addAppender(p_appender); } void LogManager::doStartup() { QMutexLocker locker(&instance()->mObjectGuard); // Override QString default_value = QLatin1String("false"); QString value = InitialisationHelper::setting(QLatin1String("DefaultInitOverride"), default_value); if (value != default_value) { static_logger()->debug("DefaultInitOverride is set. Aborting default initialisation"); return; } // Configuration using setting Configuration value = InitialisationHelper::setting(QLatin1String("Configuration")); if (QFile::exists(value)) { static_logger()->debug("Default initialisation configures from file '%1' specified by Configure", value); PropertyConfigurator::configure(value); return; } // Configuration using setting if (QCoreApplication::instance()) { const QLatin1String log4qt_group("Log4Qt"); const QLatin1String properties_group("Properties"); QSettings s; s.beginGroup(log4qt_group); if (s.childGroups().contains(properties_group)) { const QString group(QLatin1String("Log4Qt/Properties")); static_logger()->debug("Default initialisation configures from setting '%1/%2'", log4qt_group, properties_group); s.beginGroup(properties_group); PropertyConfigurator::configure(s); return; } } // Configuration using default file const QString default_file(QLatin1String("log4qt.properties")); if (QFile::exists(default_file)) { static_logger()->debug("Default initialisation configures from default file '%1'", default_file); PropertyConfigurator::configure(default_file); return; } static_logger()->debug("Default initialisation leaves package unconfigured"); } void LogManager::welcome() { static_logger()->info("Initialising Log4Qt %1", QLatin1String(LOG4QT_VERSION_STR)); // Debug: Info if (static_logger()->isDebugEnabled()) { // Create a nice timestamp with UTC offset DateTime start_time = DateTime::fromMilliSeconds(InitialisationHelper::startTime()); QString offset; { QDateTime utc = start_time.toUTC(); QDateTime local = start_time.toLocalTime(); QDateTime local_as_utc = QDateTime(local.date(), local.time(), Qt::UTC); int min = utc.secsTo(local_as_utc) / 60; if (min < 0) offset += QLatin1Char('-'); else offset += QLatin1Char('+'); min = abs(min); offset += QString::number(min / 60).rightJustified(2, QLatin1Char('0')); offset += QLatin1Char(':'); offset += QString::number(min % 60).rightJustified(2, QLatin1Char('0')); } static_logger()->debug("Program startup time is %1 (UTC%2)", start_time.toString(QLatin1String("ISO8601")), offset); static_logger()->debug("Internal logging uses the level %1", logLogger()->level().toString()); } // Trace: Dump settings if (static_logger()->isTraceEnabled()) { static_logger()->trace("Settings from the system environment:"); QString entry; Q_FOREACH (entry, InitialisationHelper::environmentSettings().keys()) static_logger()->trace(" %1: '%2'", entry, InitialisationHelper::environmentSettings().value(entry)); static_logger()->trace("Settings from the application settings:"); if (QCoreApplication::instance()) { const QLatin1String log4qt_group("Log4Qt"); const QLatin1String properties_group("Properties"); static_logger()->trace(" %1:", log4qt_group); QSettings s; s.beginGroup(log4qt_group); Q_FOREACH (entry, s.childKeys()) static_logger()->trace(" %1: '%2'", entry, s.value(entry).toString()); static_logger()->trace(" %1/%2:", log4qt_group, properties_group); s.beginGroup(properties_group); Q_FOREACH (entry, s.childKeys()) static_logger()->trace(" %1: '%2'", entry, s.value(entry).toString()); } else static_logger()->trace(" QCoreApplication::instance() is not available"); } } #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) void LogManager::qtMessageHandler(QtMsgType type, const char *pMessage) { Level level; switch (type) { case QtDebugMsg: level = Level::DEBUG_INT; break; case QtWarningMsg: level = Level::WARN_INT; break; case QtInfoMsg: level = Level::INFO_INT; break; case QtCriticalMsg: level = Level::ERROR_INT; break; case QtFatalMsg: level = Level::FATAL_INT; break; default: level = Level::TRACE_INT; } instance()->qtLogger()->log(level, pMessage); // Qt fatal behaviour copied from global.cpp qt_message_output() // begin { if ((type == QtFatalMsg) || ((type == QtWarningMsg) && (!qgetenv("QT_FATAL_WARNINGS").isNull())) ) { #if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR) // get the current report mode int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW); _CrtSetReportMode(_CRT_ERROR, reportMode); int ret = _CrtDbgReport(_CRT_ERROR, __FILE__, __LINE__, QT_VERSION_STR, pMessage); if (ret == 0 && reportMode & _CRTDBG_MODE_WNDW) return; // ignore else if (ret == 1) _CrtDbgBreak(); #endif #if defined(Q_OS_UNIX) && defined(QT_DEBUG) //abort(); // trap; generates core dump #else //exit(1); // goodbye cruel world #endif } // } end } #else void LogManager::qtMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message) { Level level; switch (type) { case QtDebugMsg: level = Level::DEBUG_INT; break; case QtWarningMsg: level = Level::WARN_INT; break; case QtInfoMsg: level = Level::INFO_INT; break; case QtCriticalMsg: level = Level::ERROR_INT; break; case QtFatalMsg: level = Level::FATAL_INT; break; default: level = Level::TRACE_INT; } QString newMsg = context.file?QString("|PID:%1|%2:%3(%4)|").arg(getpid()).arg(context.file).arg(context.line).arg(context.function):QString("|PID:%1|").arg(getpid()); instance()->qtLogger()->log(level, newMsg+message); emit instance()->qtLogger()->logOutput(); // Qt fatal behaviour copied from global.cpp qt_message_output() // begin { if ((type == QtFatalMsg) || ((type == QtWarningMsg) && (!qgetenv("QT_FATAL_WARNINGS").isNull())) ) { #if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR) // get the current report mode int reportMode = _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_WNDW); _CrtSetReportMode(_CRT_ERROR, reportMode); int ret = _CrtDbgReport(_CRT_ERROR, __FILE__, __LINE__, QT_VERSION_STR, message.toUtf8().constData()); if (ret == 0 && reportMode & _CRTDBG_MODE_WNDW) return; // ignore else if (ret == 1) _CrtDbgBreak(); #endif #if defined(Q_OS_UNIX) && defined(QT_DEBUG) //abort(); // trap; generates core dump #else //exit(1); // goodbye cruel world #endif } // } end } #endif LogManager *LogManager::mspInstance = 0; /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const LogManager &rLogManager) { Q_UNUSED(rLogManager); // To avoid warning C4100 on VS 2008 QList loggers = rLogManager.loggers(); debug.nospace() << "LogManager(" << "loggerrepository:" << *rLogManager.loggerRepository() << "log-level:" << rLogManager.logLogger()->level().toString() << "log-appenders:" << rLogManager.logLogger()->appenders().count() << "qt-level:" << rLogManager.qtLogger()->level().toString() << "qt-appenders:" << rLogManager.qtLogger()->appenders().count() << "handleqtmessages:" << rLogManager.handleQtMessages() << ")"; return debug.space(); } #endif // QT_NO_DEBUG_STREAM } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/ndc.cpp0000664000175000017500000000763215167726064017124 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: ndc.cpp * created: September 2007 * author: Martin Heinrich * * * changes Feb 2009, Martin Heinrich * - Fixed VS 2008 unreferenced formal parameter warning by using * Q_UNUSED in operator<<. * * * Copyright 2007 - 2009 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *****************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/ndc.h" #include #include #include #include "log4qt/helpers/initialisationhelper.h" #include "log4qt/logger.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ LOG4QT_DECLARE_STATIC_LOGGER(logger, Log4Qt:NDC) /************************************************************************** * Class implementation: NDC **************************************************************************/ void NDC::clear() { if (!instance()->mStack.hasLocalData()) return; instance()->mStack.localData()->clear(); } int NDC::depth() { if (!instance()->mStack.hasLocalData()) return 0; return instance()->mStack.localData()->count(); } LOG4QT_IMPLEMENT_INSTANCE(NDC) QString NDC::pop() { if (!instance()->mStack.hasLocalData() || instance()->mStack.localData()->isEmpty()) { logger()->warn("Requesting pop from empty NDC stack"); return QString(); } return instance()->mStack.localData()->pop(); } void NDC::push(const QString &rMessage) { if (!instance()->mStack.hasLocalData()) instance()->mStack.setLocalData(new QStack); instance()->mStack.localData()->push(rMessage); } void NDC::setMaxDepth(int maxDepth) { if (!instance()->mStack.hasLocalData() || instance()->mStack.localData()->size() <= maxDepth) return; instance()->mStack.localData()->resize(maxDepth); } QString NDC::peek() { if (!instance()->mStack.hasLocalData() || instance()->mStack.localData()->isEmpty()) return QString(); return instance()->mStack.localData()->top(); } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const NDC &rNDC) { Q_UNUSED(rNDC); // To avoid warning C4100 on VS 2008 debug.nospace() << "NDC(" << "thread:" << QThread::currentThread()->objectName() << " " << "peek:" << rNDC.peek() << " " << "depth:" << rNDC.depth() << ")"; return debug.space(); } #endif // QT_NO_DEBUG_STREAM } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/logmanager.h0000664000175000017500000003033415167726076020137 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: logmanager.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_LOGMANAGER_H #define LOG4QT_LOGMANAGER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include #include #include #include #include #include "log4qt/level.h" #include "log4qt/logger.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { class LoggerRepository; /*! * \brief The class LogManager manages Logger in the default * LoggerRepository. * * The LogManager manages logger in a single Hierarchy instance. It * provides access to special logger over the logLogger(), qtLogger() * and rootLogger() member functions. * * The LogManager is handling the initialisation on startup. The * initialisation procedure will first attempt to configure the package * based on environment variables. If the attempt fails it will check for * the existence of configuration files in several location. For detailed * description of the initialisation procedure see \ref Init * "Initialization procedure". * * Messages created by qDebug(), qWarning(), qCritical() and qFatal() can * be can be handled by the LogManager. By default the message handling * is disabled. It can be enabled by calling setHandleQtMessages(). Once * enabled all messages are logged using the logger qtLogger(). * * The Log4Qt runtime version is accessible over version(). The macros * \ref Log4Qt::LOG4QT_VERSION "LOG4QT_VERSION" and * \ref Log4Qt::LOG4QT_VERSION_STR "LOG4QT_VERSION_STR" provide the * compile time version. * * \note All the functions declared in this class are thread-safe. */ class LIBUKUILOG4QT_EXPORT LogManager { private: LogManager(); LogManager(const LogManager &rOther); // Not implemented virtual ~LogManager(); LogManager &operator=(const LogManager &rOther); // Not implemented public: /*! * Returns if the handling of messages created by calls to qDebug(), * qWarning(), qCritical() and qFatal() is activated. * * \sa setHandleQtMessages() */ static bool handleQtMessages(); static LoggerRepository *loggerRepository(); /*! * Returns the logger used for logging internal messages. See * \ref LogLog "Logging within the package" for more details. * * Calling this function is equivalent to calling logger("Log4Qt"). */ static Logger *logLogger(); /*! * Returns a pointer to the logger used for logging messages created by * calls to qDebug(), qWarning(), qCritical() and qFatal(). * * Calling this function is equivalent to calling logger("Qt"). * * \sa setHandleQtMessages() */ static Logger *qtLogger(); static Logger *rootLogger(); static QList loggers(); static Level threshold(); static void setThreshold(Level level); /*! * Activates or deactivates the handling of messages created by calls * to qDebug(), qWarning(), qCritical() and qFatal() is activated. * * If activated, a Qt message handler is installed. Messages are logged * using the logger returned by qtLogger(). For fatal messages the same * exit procedure is implemented as for qFatal(). * * The following mappping is used from QtMsgType to Level: * * * * * * * * * * * * * * * * * * * * * *
    QtMsgType     %Level
QtDebugMsg Level::DEBUG_INT
QtWarningMsg Level::WARN_INT
QtCriticalMsg Level::ERROR_INT
QtFatalMsg Level::FATAL_INT
QtSystemMsg Level::TRACE_INT
* * The default value is false for not handling Qt messages. * * \sa handleQtMessages(), qInstallMsgHandler(), qFatal() */ static void setHandleQtMessages(bool handleQtMessages); /*! * Configures the logging for the package to its default behaviour. * * The logger logLogger() is configured to be not additive. Messages * with the level Level::ERROR_INT and Level::FATAL_INT are written * to \c stderr using a ConsoleAppender. The remaining messages are * written to \c stdout using a second ConsoleAppender. The level is * read from the system environment or application settings using * InitialisationHelper::setting() with the key \c Debug. If a level * value is found, but it is not a valid Level string, * Level::DEBUG_INT is used. If no level string is found * Level::ERROR_INT is used. * * The function does not remove any appender from the logger * logLogger(). * * \sa \ref LogLog "Logging within the package", * \ref Env "Environment Variables", * resetConfiguration(), InitialisationHelper::setting() */ static void configureLogLogger(); static bool exists(const char *pName); // JAVA: void fireAddAppenderEvent(Logger *pLogger, Appender *pAppender); /*! * Returns the LogManager instance. */ static LogManager *instance(); static Logger *logger(const QString &rName); /*! * Reset all values contained in logger repository to their default. * * All appenders are removed from all loggers. The loggers are handled * in no particular order. The last loggers to be reset are qtLogger(), * logLogger() and rootLogger() in that order. * * The handling of messages created by calls to qDebug(), qWarning(), * qCritical() and qFatal() is deactivated. * * The internal logging is initialised to its default bahaviour * using configureLogLogger(). * * \sa LoggerRepository::resetConfiguration(), setHandleQtMessages(), * configureLogLogger() */ static void resetConfiguration(); static void shutdown(); /*! * Executes the default initialisation procedure of the package. * * The function will test for the setting \c DefaultInitOverride in * the system environment and application settings using * \ref InitialisationHelper::setting(). If the value is present and * set to anything else then \c false, the initialisation is aborted. *
* The system environment and application settings are tested for the * setting \c Configuration. If it is found and it is a valid path to * a file, the package is configured with the file using * \ref PropertyConfigurator::doConfigure(const QString &, LoggerRepository *) * "PropertyConfigurator::doConfigure()". If the setting * \c Configuration is not available and a QCoreApplication object is * present, the application settings are tested for a group * \c Log4Qt/Properties. If the group exists, the package is configured * with the setting using the * \ref PropertyConfigurator::doConfigure(const QSettings &r, LoggerRepository *) * "PropertyConfiguratordoConfigure()". If neither a configuration * file nor configuration settings could be found, the current working * directory is searched for the file \c "log4qt.properties". If it is * found, the package is configured with the file using * \ref PropertyConfigurator::doConfigure(const QString &, LoggerRepository *) * "PropertyConfigurator::doConfigure()". * * \sa \ref Init "Initialization procedure", * \ref Env "Environment Variables", * InitialisationHelper::setting() */ static void startup(); /*! * Returns the version number of Log4Qt at run-time. This may be a * different version than the version the application was compiled * against. * * \sa \ref Log4Qt::LOG4QT_VERSION "LOG4QT_VERSION", * \ref Log4Qt::LOG4QT_VERSION_STR "LOG4QT_VERSION_STR" */ static const char* version(); private: void doSetHandleQtMessages(bool handleQtMessages); void doConfigureLogLogger(); void doStartup(); void welcome(); #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) static void qtMessageHandler(QtMsgType type, const char *pMessage); #else static void qtMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &message); #endif private: #if QT_VERSION < 0x050E00 mutable QMutex mObjectGuard; #else mutable QRecursiveMutex mObjectGuard; #endif LoggerRepository *mpLoggerRepository; Logger *mpNullLogger; bool mHandleQtMessages; #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) QtMsgHandler mOldQtMsgHandler; #else QtMessageHandler mOldQtMsgHandler; #endif static LogManager *mspInstance; }; /*************************************************************************** * Operators, Helper ***************************************************************************/ #ifndef QT_NO_DEBUG_STREAM /*! * \relates LogManager * * Writes all object member variables to the given debug stream \a rDebug and * returns the stream. * * * %LogManager(loggerrepository:Hierarchy(loggers:6 root-level:"DEBUG" * root-appenders:0 log-level: "NULL" log-appenders:0 * qt-level: "NULL" qt-appenders:0 handleqtmessages: false ) * * \sa QDebug */ QDebug operator<<(QDebug debug, const LogManager &rLogManager); #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Inline **************************************************************************/ inline LoggerRepository *LogManager::loggerRepository() { // QMutexLocker locker(&instance()->mObjectGuard); // Constant for object lifetime return instance()->mpLoggerRepository; } inline bool LogManager::handleQtMessages() { // QMutexLocker locker(&instance()->mObjectGuard); // Read/Write of bool is safe return instance()->mHandleQtMessages; } inline Logger *LogManager::logLogger() { // QMutexLocker locker(&instance()->mObjectGuard); // Constant for object lifetime return logger(QLatin1String("Log4Qt")); } inline Logger *LogManager::qtLogger() { // QMutexLocker locker(&instance()->mObjectGuard); // Constant for object lifetime return logger(QLatin1String("Qt")); } inline void LogManager::setHandleQtMessages(bool handleQtMessages) { instance()->doSetHandleQtMessages(handleQtMessages); } inline void LogManager::configureLogLogger() { instance()->doConfigureLogLogger(); } inline void LogManager::startup() { instance()->doStartup(); } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::LogManager, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_LOGMANAGER_H ukui-interface/src/log4qt/log4qt/dailyrollingfileappender.cpp0000664000175000017500000004100615167726076023424 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: dailyrollingfileappender.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/dailyrollingfileappender.h" #include #include #include #include #if QT_VERSION < 0x060000 #include #endif #include "log4qt/helpers/datetime.h" #include "log4qt/layout.h" #include "log4qt/loggingevent.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: DailyRollingFileAppender **************************************************************************/ DailyRollingFileAppender::DailyRollingFileAppender(QObject *pParent) : FileAppender(pParent), mDatePattern() { setDatePattern(DAILY_ROLLOVER); } DailyRollingFileAppender::DailyRollingFileAppender(Layout *pLayout, const QString &rFileName, const QString &rDatePattern, QObject *pParent) : FileAppender(pLayout, rFileName, pParent), mDatePattern() { setDatePattern(rDatePattern); } DailyRollingFileAppender::~DailyRollingFileAppender() { close(); } void DailyRollingFileAppender::setDatePattern(DatePattern datePattern) { switch (datePattern) { case MINUTELY_ROLLOVER: setDatePattern(QLatin1String("'.'yyyy-MM-dd-hh-mm")); break; case HOURLY_ROLLOVER: setDatePattern(QLatin1String("'.'yyyy-MM-dd-hh")); break; case HALFDAILY_ROLLOVER: setDatePattern(QLatin1String("'.'yyyy-MM-dd-a")); break; case DAILY_ROLLOVER: setDatePattern(QLatin1String("'.'yyyy-MM-dd")); break; case WEEKLY_ROLLOVER: setDatePattern(QLatin1String("'.'yyyy-ww")); break; case MONTHLY_ROLLOVER: setDatePattern(QLatin1String("'.'yyyy-MM")); break; default: Q_ASSERT_X(false, "DailyRollingFileAppender::setDatePattern()", "Invalid datePattern constant"); setDatePattern(DAILY_ROLLOVER); }; } void DailyRollingFileAppender::activateOptions() { QMutexLocker locker(&mObjectGuard); computeFrequency(); if (!mActiveDatePattern.isEmpty()) { #ifdef UKUILOG4QT_EXTRA_ENABLE QFileInfo fileInfo(file()); if (!fileInfo.exists()) { computeRollOverTime(); } else { computeRollOverTime(fileInfo.birthTime().isNull()?fileInfo.lastModified():fileInfo.birthTime()); } #else computeRollOverTime(); #endif FileAppender::activateOptions(); } } void DailyRollingFileAppender::append(const LoggingEvent &rEvent) { // Q_ASSERT_X(, "DailyRollingFileAppender::append()", "Lock must be held by caller") if (QDateTime::currentDateTime() > mRollOverTime) rollOver(); FileAppender::append(rEvent); } void DailyRollingFileAppender::asyncAppend(const LoggingEvent &rEvent) { // Q_ASSERT_X(, "DailyRollingFileAppender::asyncAppend()", "Lock must be held by caller") if (QDateTime::currentDateTime() > mRollOverTime) rollOver(); FileAppender::asyncAppend(rEvent); } bool DailyRollingFileAppender::checkEntryConditions() const { // Q_ASSERT_X(, "DailyRollingFileAppender::checkEntryConditions()", "Lock must be held by caller") if (mActiveDatePattern.isEmpty()) { LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Use of appender '%1' without having a valid date pattern set"), APPENDER_USE_INVALID_PATTERN_ERROR); e << name(); logger()->error(e); return false; } return FileAppender::checkEntryConditions(); } #ifndef QT_NO_DEBUG_STREAM QDebug DailyRollingFileAppender::debug(QDebug &rDebug) const { QString layout_name; if (layout()) layout_name = layout()->name(); QString codec_name; #if QT_VERSION < 0x060000 if (encoding()) codec_name = QLatin1String(encoding()->name()); #else codec_name = QLatin1String(QStringConverter::nameForEncoding(encoding())); #endif rDebug.nospace() << "DailyRollingFileAppender(" << "name:" << name() << " " << "activedatepattern:" << mActiveDatePattern << " " << "appendfile:" << appendFile() << " " << "bufferedio:" << bufferedIo() << " " << "datepattern:" << datePattern() << " " << "encoding:" << codec_name << " " << "frequency:" << frequencyToString() << " " << "file:" << file() << " " << "filter:" << firstFilter() << " " << "immediateflush:" << immediateFlush() << " " << "isactive:" << isActive() << " " << "isclosed:" << isClosed() << " " << "layout:" << layout_name << " " << "referencecount:" << referenceCount() << " " << "rollovertime:" << mRollOverTime << "threshold:" << threshold().toString() << "writer:" << writer() << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM void DailyRollingFileAppender::computeFrequency() { // Q_ASSERT_X(, "DailyRollingFileAppender::computeFrequency()", "Lock must be held by caller") const DateTime start_time(QDate(1999, 1, 1), QTime(0, 0)); const QString start_string = start_time.toString(mDatePattern); mActiveDatePattern.clear(); if (start_string != static_cast(start_time.addSecs(60)).toString(mDatePattern)) mFrequency = MINUTELY_ROLLOVER; else if (start_string != static_cast(start_time.addSecs(60 * 60)).toString(mDatePattern)) mFrequency = HOURLY_ROLLOVER; else if (start_string != static_cast(start_time.addSecs(60 * 60 * 12)).toString(mDatePattern)) mFrequency = HALFDAILY_ROLLOVER; else if (start_string != static_cast(start_time.addDays(1)).toString(mDatePattern)) mFrequency = DAILY_ROLLOVER; else if (start_string != static_cast(start_time.addDays(7)).toString(mDatePattern)) mFrequency = WEEKLY_ROLLOVER; else if (start_string != static_cast(start_time.addMonths(1)).toString(mDatePattern)) mFrequency = MONTHLY_ROLLOVER; else { LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("The pattern '%1' does not specify a frequency for appender '%2'"), APPENDER_INVALID_PATTERN_ERROR); e << mDatePattern << name(); logger()->error(e); return; } mActiveDatePattern = mDatePattern; logger()->trace("Frequency set to %2 using date pattern %1", mActiveDatePattern, frequencyToString()); } void DailyRollingFileAppender::computeRollOverTime(QDateTime startTime) { // Q_ASSERT_X(, "DailyRollingFileAppender::computeRollOverTime()", "Lock must be held by caller") Q_ASSERT_X(!mActiveDatePattern.isEmpty(), "DailyRollingFileAppender::computeRollOverTime()", "No active date pattern"); QDateTime now = startTime; QDate now_date = now.date(); QTime now_time = now.time(); QDateTime start; switch (mFrequency) { case MINUTELY_ROLLOVER: { start = QDateTime(now_date, QTime(now_time.hour(), now_time.minute(), 0, 0)); mRollOverTime = start.addSecs(60); } break; case HOURLY_ROLLOVER: { start = QDateTime(now_date, QTime(now_time.hour(), 0, 0, 0)); mRollOverTime = start.addSecs(60*60); } break; case HALFDAILY_ROLLOVER: { int hour = now_time.hour(); if (hour >= 12) hour = 12; else hour = 0; start = QDateTime(now_date, QTime(hour, 0, 0, 0)); mRollOverTime = start.addSecs(60*60*12); } break; case DAILY_ROLLOVER: { start = QDateTime(now_date, QTime(0, 0, 0, 0)); mRollOverTime = start.addDays(1); } break; case WEEKLY_ROLLOVER: { // QT numbers the week days 1..7. The week starts on Monday. // Change it to being numbered 0..6, starting with Sunday. int day = now_date.dayOfWeek(); if (day == Qt::Sunday) day = 0; start = QDateTime(now_date, QTime(0, 0, 0, 0)).addDays(-1 * day); mRollOverTime = start.addDays(7); } break; case MONTHLY_ROLLOVER: { start = QDateTime(QDate(now_date.year(), now_date.month(), 1), QTime(0, 0, 0, 0)); mRollOverTime = start.addMonths(1); } break; default: Q_ASSERT_X(false, "DailyRollingFileAppender::computeInterval()", "Invalid datePattern constant"); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) mRollOverTime = QDateTime::fromTime_t(0); #else mRollOverTime = QDateTime::fromSecsSinceEpoch(0); #endif } mRollOverSuffix = static_cast(start).toString(mActiveDatePattern); Q_ASSERT_X(static_cast(now).toString(mActiveDatePattern) == mRollOverSuffix, "DailyRollingFileAppender::computeRollOverTime()", "File name changes within interval"); Q_ASSERT_X(mRollOverSuffix != static_cast(mRollOverTime).toString(mActiveDatePattern), "DailyRollingFileAppender::computeRollOverTime()", "File name does not change with rollover"); logger()->trace("Computing roll over time from %1: The interval start time is %2. The roll over time is %3", now, start, mRollOverTime); } void DailyRollingFileAppender::computeRollOverTime() { // Q_ASSERT_X(, "DailyRollingFileAppender::computeRollOverTime()", "Lock must be held by caller") Q_ASSERT_X(!mActiveDatePattern.isEmpty(), "DailyRollingFileAppender::computeRollOverTime()", "No active date pattern"); QDateTime now = QDateTime::currentDateTime(); QDate now_date = now.date(); QTime now_time = now.time(); QDateTime start; switch (mFrequency) { case MINUTELY_ROLLOVER: { start = QDateTime(now_date, QTime(now_time.hour(), now_time.minute(), 0, 0)); mRollOverTime = start.addSecs(60); } break; case HOURLY_ROLLOVER: { start = QDateTime(now_date, QTime(now_time.hour(), 0, 0, 0)); mRollOverTime = start.addSecs(60*60); } break; case HALFDAILY_ROLLOVER: { int hour = now_time.hour(); if (hour >= 12) hour = 12; else hour = 0; start = QDateTime(now_date, QTime(hour, 0, 0, 0)); mRollOverTime = start.addSecs(60*60*12); } break; case DAILY_ROLLOVER: { start = QDateTime(now_date, QTime(0, 0, 0, 0)); mRollOverTime = start.addDays(1); } break; case WEEKLY_ROLLOVER: { // QT numbers the week days 1..7. The week starts on Monday. // Change it to being numbered 0..6, starting with Sunday. int day = now_date.dayOfWeek(); if (day == Qt::Sunday) day = 0; start = QDateTime(now_date, QTime(0, 0, 0, 0)).addDays(-1 * day); mRollOverTime = start.addDays(7); } break; case MONTHLY_ROLLOVER: { start = QDateTime(QDate(now_date.year(), now_date.month(), 1), QTime(0, 0, 0, 0)); mRollOverTime = start.addMonths(1); } break; default: Q_ASSERT_X(false, "DailyRollingFileAppender::computeInterval()", "Invalid datePattern constant"); #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) mRollOverTime = QDateTime::fromTime_t(0); #else mRollOverTime = QDateTime::fromSecsSinceEpoch(0); #endif } mRollOverSuffix = static_cast(start).toString(mActiveDatePattern); Q_ASSERT_X(static_cast(now).toString(mActiveDatePattern) == mRollOverSuffix, "DailyRollingFileAppender::computeRollOverTime()", "File name changes within interval"); Q_ASSERT_X(mRollOverSuffix != static_cast(mRollOverTime).toString(mActiveDatePattern), "DailyRollingFileAppender::computeRollOverTime()", "File name does not change with rollover"); logger()->trace("Computing roll over time from %1: The interval start time is %2. The roll over time is %3", now, start, mRollOverTime); } QString DailyRollingFileAppender::frequencyToString() const { QMetaEnum meta_enum = metaObject()->enumerator(metaObject()->indexOfEnumerator("DatePattern")); return QLatin1String(meta_enum.valueToKey(mFrequency)); } void DailyRollingFileAppender::rollOver() { // Q_ASSERT_X(, "DailyRollingFileAppender::rollOver()", "Lock must be held by caller") Q_ASSERT_X(!mActiveDatePattern.isEmpty(), "DailyRollingFileAppender::rollOver()", "No active date pattern"); QString roll_over_suffix = mRollOverSuffix; computeRollOverTime(); if (roll_over_suffix == mRollOverSuffix) return; closeFile(); QString target_file_name = file() + roll_over_suffix; QFile f(target_file_name); if (f.exists() && !removeFile(f)) return; f.setFileName(file()); if (!renameFile(f, target_file_name)) return; openFile(); } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/mdc.cpp0000664000175000017500000000616015167726064017116 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: mdc.cpp * created: September 2007 * author: Martin Heinrich * * * changes Feb 2009, Martin Heinrich * - Fixed unreferenced formal parameter warning by using * Q_UNUSED in operator<<. * * * Copyright 2007 - 2009 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *****************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/mdc.h" #include #include #include #include "log4qt/helpers/initialisationhelper.h" #include "log4qt/logger.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: MDC **************************************************************************/ QString MDC::get(const QString &rKey) { if (!instance()->mHash.hasLocalData()) return QString(); return instance()->mHash.localData()->value(rKey); } QHash MDC::context() { if (!instance()->mHash.hasLocalData()) return QHash(); return *instance()->mHash.localData(); } LOG4QT_IMPLEMENT_INSTANCE(MDC) QHash *MDC::localData() { if (!instance()->mHash.hasLocalData()) instance()->mHash.setLocalData(new QHash); return instance()->mHash.localData(); } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const MDC &rMDC) { Q_UNUSED(rMDC); // To avoid warning C4100 on VS 2008 debug.nospace() << "MDC(" << "thread:" << QThread::currentThread()->objectName() << " " << "context:" << rMDC.context() << ")"; return debug.space(); } #endif // QT_NO_DEBUG_STREAM } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/loggingevent.h0000664000175000017500000001574415167726064020520 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: loggingevent.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_LOG4QTEVENT_H #define LOG4QT_LOG4QTEVENT_H /****************************************************************************** * Dependencies ******************************************************************************/ #include #include #include #include #include #include "log4qt/level.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { class Logger; /*! * \brief The class LoggingEvent is the internal representation of a * logging event. * * The class uses milliseconds since 1970-01-01T00:00:00, Coordinated * Universal Time for time values. For converstion from and to QDateTime * use DateTime. */ class LIBUKUILOG4QT_EXPORT LoggingEvent : public QEvent { public: static const QEvent::Type eventId; LoggingEvent(); LoggingEvent(const Logger *pLogger, Level level, const QString &rMessage); LoggingEvent(const Logger *pLogger, Level level, const QString &rMessage, qint64 timeStamp); LoggingEvent(const Logger *pLogger, Level level, const QString &rMessage, const QString &rNdc, const QHash &rProperties, const QString &rThreadName, qint64 timeStamp); // LoggingEvent(const LoggingEvent &LoggingEvent::rOther); // Use compiler default // virtual ~LoggingEvent(); // Use compiler default // LoggingEvent &operator=(const LoggingEvent &LoggingEvent::rOther); // Use compiler default // JAVA: QString fqnOfLoggerClass() const; Level level() const; // LocationInformation locationInformation() const; const Logger *logger() const; QString message() const; QHash mdc() const; QString ndc() const; QHash properties() const; qint64 sequenceNumber() const; QString threadName() const; // JAVA: ThrowableInformation throwableInformation() const; qint64 timeStamp() const; // JAVA: bool locationInformationExists() const; QString loggerName() const; QString property(const QString &rKey) const; QStringList propertyKeys() const; void setProperty(const QString &rKey, const QString &rValue); // JAVA: QString throwableStrRep() const; QString toString() const; static qint64 sequenceCount(); static qint64 startTime(); private: void setThreadNameToCurrent(); static qint64 nextSequenceNumber(); private: Level mLevel; const Logger *mpLogger; QString mMessage; QString mNdc; QHash mProperties; qint64 mSequenceNumber; QString mThreadName; qint64 mTimeStamp; static qint64 msSequenceCount; #ifndef QT_NO_DATASTREAM // Needs to be friend to stream objects friend QDataStream &operator<<(QDataStream &rStream, const LoggingEvent &rLoggingEvent); friend QDataStream &operator>>(QDataStream &rStream, LoggingEvent &rLoggingEvent); #endif // QT_NO_DATASTREAM }; /************************************************************************** * Operators, Helper **************************************************************************/ #ifndef QT_NO_DATASTREAM /*! * \relates LoggingEvent * * Writes the given error \a rLoggingEvent to the given stream \a rStream, * and returns a reference to the stream. */ QDataStream &operator<<(QDataStream &rStream, const LoggingEvent &rLoggingEvent); /*! * \relates LoggingEvent * * Reads an error from the given stream \a rStream into the given * error \a rLoggingEvent, and returns a reference to the stream. */ QDataStream &operator>>(QDataStream &rStream, LoggingEvent &rLoggingEvent); #endif // QT_NO_DATASTREAM #ifndef QT_NO_DEBUG_STREAM /*! * \relates LoggingEvent * * Writes all object member variables to the given debug stream \a debug and * returns the stream. * * * %LoggingEvent(level:"WARN" logger:"Log4Qt::Properties" * message:"Unknown escape sequence '\j' in property starting at line 1" * sequencenumber:14 threadname:"main" * timestamp:1194337148937(QDateTime("Tue Nov 6 03:19:08 2007") ) * sequenceCount: 14 ) * * * \sa QDebug */ QDebug operator<<(QDebug debug, const LoggingEvent &rLoggingEvent); #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Inline **************************************************************************/ inline Level LoggingEvent::level() const { return mLevel; } inline const Logger *LoggingEvent::logger() const { return mpLogger; } inline QString LoggingEvent::message() const { return mMessage; } inline QHash LoggingEvent::mdc() const { return mProperties; } inline QString LoggingEvent::ndc() const { return mNdc; } inline QHash LoggingEvent::properties() const { return mProperties; } inline qint64 LoggingEvent::sequenceNumber() const { return mSequenceNumber; } inline QString LoggingEvent::threadName() const { return mThreadName; } inline qint64 LoggingEvent::timeStamp() const { return mTimeStamp; } inline QString LoggingEvent::property(const QString &rKey) const { return mProperties.value(rKey); } inline QStringList LoggingEvent::propertyKeys() const { return QStringList(mProperties.keys()); } inline void LoggingEvent::setProperty(const QString &rKey, const QString &rValue) { mProperties.insert(rKey, rValue); } } // namespace Log4Qt Q_DECLARE_METATYPE(Log4Qt::LoggingEvent) Q_DECLARE_TYPEINFO(Log4Qt::LoggingEvent, Q_MOVABLE_TYPE); #endif // LOG4QT_LOG4QTEVENT_H ukui-interface/src/log4qt/log4qt/dailyrollingfileappender.h0000664000175000017500000001527415167726064023076 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: dailyrollingfileappender.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_DAILYROLLINGFILEAPPENDER_H #define LOG4QT_DAILYROLLINGFILEAPPENDER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/fileappender.h" #include "ukui-logmacros.h" #include /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * \brief The class DailyRollingFileAppender extends FileAppender so that the * underlying file is rolled over at a specified frequency. * * \note All the functions declared in this class are thread-safe. * * \note The ownership and lifetime of objects of this class are managed. See * \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT DailyRollingFileAppender : public FileAppender { Q_OBJECT /*! * The property holds the date pattern used by the appender. * * The default is DAILY_ROLLOVER for rollover at midnight each day. * * \sa datePattern(), setDatePattern() */ Q_PROPERTY(QString datePattern READ datePattern WRITE setDatePattern) public: /*! * The enum DatePattern defines constants for date patterns. * * \sa setDatePattern(DatePattern) */ enum DatePattern { /*! The minutely date pattern string is "'.'yyyy-MM-dd-hh-mm". */ MINUTELY_ROLLOVER = 0, /*! The hourly date pattern string is "'.'yyyy-MM-dd-hh". */ HOURLY_ROLLOVER, /*! The half-daily date pattern string is "'.'yyyy-MM-dd-a". */ HALFDAILY_ROLLOVER, /*! The daily date pattern string is "'.'yyyy-MM-dd". */ DAILY_ROLLOVER, /*! The weekly date pattern string is "'.'yyyy-ww". */ WEEKLY_ROLLOVER, /*! The monthly date pattern string is "'.'yyyy-MM". */ MONTHLY_ROLLOVER }; Q_ENUMS(DatePattern) DailyRollingFileAppender(QObject *pParent = 0); DailyRollingFileAppender(Layout *pLayout, const QString &rFileName, const QString &rDatePattern, QObject *pParent = 0); virtual ~DailyRollingFileAppender(); private: DailyRollingFileAppender(const DailyRollingFileAppender &rOther); // Not implemented DailyRollingFileAppender &operator=(const DailyRollingFileAppender &rOther); // Not implemented public: QString datePattern() const; /*! * Sets the datePattern to the value specified by the \a datePattern * constant. */ void setDatePattern(DatePattern datePattern); void setDatePattern(const QString &rDatePattern); virtual void activateOptions(); protected: virtual void append(const LoggingEvent &rEvent); virtual void asyncAppend(const LoggingEvent &rEvent); /*! * Tests if all entry conditions for using append() in this class are * met. * * If a conditions is not met, an error is logged and the function * returns false. Otherwise the result of * FileAppender::checkEntryConditions() is returned. * * The checked conditions are: * - A valid pattern has been set (APPENDER_USE_INVALID_PATTERN_ERROR) * * The function is called as part of the checkEntryConditions() chain * started by AppenderSkeleton::doAppend(). * * \sa AppenderSkeleton::doAppend(), * AppenderSkeleton::checkEntryConditions() */ virtual bool checkEntryConditions() const; protected: #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream * \a rDebug and returns the stream. * * * %DailyRollingFileAppender(name:"DRFA" activedatepattern:"'.'yyyy-MM-dd-hh-mm" * appendfile:false bufferedio:true * datepattern:"'.'yyyy-MM-dd-hh-mm" * encoding:"" frequency:"MINUTELY_ROLLOVER" * file:"/log.txt" filter:0x0 immediateflush:true * isactive:true isclosed:false layout:"TTCC" * referencecount:1 * rollovertime:QDateTime("Mon Oct 22 05:23:00 2007") * threshold: "NULL" writer: 0x0 ) * * \sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const; #endif // QT_NO_DEBUG_STREAM private: void computeFrequency(); void computeRollOverTime(); void computeRollOverTime(QDateTime startTime); QString frequencyToString() const; void rollOver(); private: QString mDatePattern; DatePattern mFrequency; QString mActiveDatePattern; QDateTime mRollOverTime; QString mRollOverSuffix; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline QString DailyRollingFileAppender::datePattern() const { QMutexLocker locker(&mObjectGuard); return mDatePattern; } inline void DailyRollingFileAppender::setDatePattern(const QString &rDatePattern) { QMutexLocker locker(&mObjectGuard); mDatePattern = rDatePattern; } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::DailyRollingFileAppender, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_DAILYROLLINGFILEAPPENDER_H ukui-interface/src/log4qt/log4qt/level.cpp0000664000175000017500000001762015167726064017465 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: level.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/level.h" #include #include #include #include "log4qt/logger.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ LOG4QT_DECLARE_STATIC_LOGGER(logger, Log4Qt::Level) /************************************************************************** * Class implementation: Level **************************************************************************/ int Level::syslogEquivalent() const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe switch (mValue) { case NULL_INT: case ALL_INT: case TRACE_INT: case DEBUG_INT: return 7; case INFO_INT: return 6; case WARN_INT: return 4; case ERROR_INT: return 3; case FATAL_INT: case OFF_INT: return 0; default: Q_ASSERT_X(false, "Level::syslogEquivalent()", "Unknown level value"); return 7; } } QString Level::toString() const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe const char *p_context = "Level"; switch (mValue) { case NULL_INT: return QCoreApplication::translate(p_context, "NULL"); case ALL_INT: return QCoreApplication::translate(p_context, "ALL"); case TRACE_INT: return QCoreApplication::translate(p_context, "TRACE"); case DEBUG_INT: return QCoreApplication::translate(p_context, "DEBUG"); case INFO_INT: return QCoreApplication::translate(p_context, "INFO"); case WARN_INT: return QCoreApplication::translate(p_context, "WARN"); case ERROR_INT: return QCoreApplication::translate(p_context, "ERROR"); case FATAL_INT: return QCoreApplication::translate(p_context, "FATAL"); case OFF_INT: return QCoreApplication::translate(p_context, "OFF"); default: Q_ASSERT_X(false, "Level::toString()", "Unknown level value"); return QCoreApplication::translate(p_context, "NULL"); } } Level Level::fromString(const QString &rLevel, bool *pOk) { const char *p_context = "Level"; if (pOk) *pOk = true; #if 1 if (!rLevel.compare(QLatin1String("OFF"), Qt::CaseInsensitive) || !rLevel.compare(QCoreApplication::translate(p_context, "OFF"), Qt::CaseInsensitive)) return OFF_INT; if (!rLevel.compare(QLatin1String("FATAL"), Qt::CaseInsensitive) || !rLevel.compare(QCoreApplication::translate(p_context, "FATAL"), Qt::CaseInsensitive)) return FATAL_INT; if (!rLevel.compare(QLatin1String("ERROR"), Qt::CaseInsensitive) || !rLevel.compare(QCoreApplication::translate(p_context, "ERROR"), Qt::CaseInsensitive)) return ERROR_INT; if (!rLevel.compare(QLatin1String("WARN"), Qt::CaseInsensitive) || !rLevel.compare(QCoreApplication::translate(p_context, "WARN"), Qt::CaseInsensitive)) return WARN_INT; if (!rLevel.compare(QLatin1String("INFO"), Qt::CaseInsensitive) || !rLevel.compare(QCoreApplication::translate(p_context, "INFO"), Qt::CaseInsensitive)) return INFO_INT; if (!rLevel.compare(QLatin1String("DEBUG"), Qt::CaseInsensitive) || !rLevel.compare(QCoreApplication::translate(p_context, "DEBUG"), Qt::CaseInsensitive)) return DEBUG_INT; if (!rLevel.compare(QLatin1String("TRACE"), Qt::CaseInsensitive) || !rLevel.compare(QCoreApplication::translate(p_context, "TRACE"), Qt::CaseInsensitive)) return TRACE_INT; if (!rLevel.compare(QLatin1String("ALL"), Qt::CaseInsensitive) || !rLevel.compare(QCoreApplication::translate(p_context, "ALL"), Qt::CaseInsensitive)) return ALL_INT; if (!rLevel.compare(QLatin1String("NULL"), Qt::CaseInsensitive) || !rLevel.compare(QCoreApplication::translate(p_context, "NULL"), Qt::CaseInsensitive)) return NULL_INT; logger()->warn("Use of invalid level string '%1'. Using 'Level::OFF_INT' instead.", rLevel); if (pOk) *pOk = false; return OFF_INT; #else if (rLevel == QLatin1String("OFF") || rLevel == QCoreApplication::translate(p_context, "OFF")) return OFF_INT; if (rLevel == QLatin1String("FATAL") || rLevel == QCoreApplication::translate(p_context, "FATAL")) return FATAL_INT; if (rLevel == QLatin1String("ERROR") || rLevel == QCoreApplication::translate(p_context, "ERROR")) return ERROR_INT; if (rLevel == QLatin1String("WARN") || rLevel == QCoreApplication::translate(p_context, "WARN")) return WARN_INT; if (rLevel == QLatin1String("INFO") || rLevel == QCoreApplication::translate(p_context, "INFO")) return INFO_INT; if (rLevel == QLatin1String("DEBUG") || rLevel == QCoreApplication::translate(p_context, "DEBUG")) return DEBUG_INT; if (rLevel == QLatin1String("TRACE") || rLevel == QCoreApplication::translate(p_context, "TRACE")) return TRACE_INT; if (rLevel == QLatin1String("ALL") || rLevel == QCoreApplication::translate(p_context, "ALL")) return ALL_INT; if (rLevel == QLatin1String("NULL") || rLevel == QCoreApplication::translate(p_context, "NULL")) return NULL_INT; logger()->warn("Use of invalid level string '%1'. Using 'Level::NULL_INT' instead.", rLevel); if (pOk) *pOk = false; return NULL_INT; #endif } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DATASTREAM QDataStream &operator<<(QDataStream &rStream, const Level &rLevel) { quint8 l = rLevel.mValue; rStream << l; return rStream; } QDataStream &operator>>(QDataStream &rStream, Level &rLevel) { quint8 l; rStream >> l; rLevel.mValue = (Level::Value)l; return rStream; } #endif // QT_NO_DATASTREAM #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const Level &rLevel) { debug.nospace() << "Level(" << rLevel.toString() << ")"; return debug.space(); } #endif // QT_NO_DEBUG_STREAM } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/varia/0000775000175000017500000000000015167726064016746 5ustar fengfengukui-interface/src/log4qt/log4qt/varia/denyallfilter.h0000664000175000017500000000637215167726064021765 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: denyallfilter.h * created: September 2007 * author: Martin Heinrich * * * changes Feb 2009, Martin Heinrich * - Fixed a compile error on VS 2008 by using Q_UNUSED(&rEvent) * instead of Q_UNUSED(rEvent) * * * Copyright 2007 - 2009 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_DENYALLFILTER_H #define LOG4QT_DENYALLFILTER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/spi/filter.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * \brief The class DenyAllFilter drops all logging events * * \note The ownership and lifetime of objects of this class are managed. * See \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT DenyAllFilter : public Filter { Q_OBJECT public: DenyAllFilter(QObject *pParent = 0); // DenyAllFilter(const DenyAllFilter &rOther); // Use compiler default // virtual ~DenyAllFilter(); // Use compiler default // DenyAllFilter &operator=(const DenyAllFilter &rOther); // Use compiler default virtual Decision decide(const LoggingEvent &rEvent) const; protected: #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream \a rDebug * and returns the stream. * * * %DenyAllFilter(next:QObject(0x0) referencecount:1 ) * * \sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const; #endif // QT_NO_DEBUG_STREAM }; /************************************************************************* * Operators, Helper *************************************************************************/ /************************************************************************* * Inline *************************************************************************/ inline DenyAllFilter::DenyAllFilter(QObject *pParent) : Filter(pParent) {} inline Filter::Decision DenyAllFilter::decide(const LoggingEvent &rEvent) const { Q_UNUSED(&rEvent); return Filter::DENY; } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::DenyAllFilter, Q_MOVABLE_TYPE); // Use default #endif // LOG4QT_DENYALLFILTER_H ukui-interface/src/log4qt/log4qt/varia/nullappender.cpp0000664000175000017500000000545415167726064022153 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: nullappender.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/varia/nullappender.h" #include #include "log4qt/layout.h" #include "log4qt/loggingevent.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: NullAppender **************************************************************************/ NullAppender::NullAppender(QObject *pParent) : AppenderSkeleton(false, pParent) { } NullAppender::~NullAppender() { close(); } void NullAppender::append(const LoggingEvent &rEvent) { Q_UNUSED(rEvent); } void NullAppender::asyncAppend(const LoggingEvent &rEvent) { Q_UNUSED(rEvent); } #ifndef QT_NO_DEBUG_STREAM QDebug NullAppender::debug(QDebug &rDebug) const { QString layout_name; if (layout()) layout_name = layout()->name(); rDebug.nospace() << "NullAppender(" << "name:" << name() << " " << "isactive:" << isActive() << " " << "isclosed:" << isClosed() << " " << "layout:" << layout_name << " " << "threshold:" << threshold().toString() << " " << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/varia/debugappender.cpp0000664000175000017500000001061015167726064022255 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: debugappender.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/varia/debugappender.h" #include #include #include "log4qt/layout.h" #include "log4qt/loggingevent.h" #if defined(Q_WS_WIN) || defined(Q_OS_WIN32) #include #endif namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: DebugAppender **************************************************************************/ DebugAppender::DebugAppender(Layout *pLayout, QObject *pParent) : AppenderSkeleton(pParent) { setLayout(pLayout); } bool DebugAppender::requiresLayout() const { return true; } void DebugAppender::append(const LoggingEvent &rEvent) { // Q_ASSERT_X(, "DebugAppender::append()", "Lock must be held by caller"); Q_ASSERT_X(layout(), "DebugAppender::append()", "Layout must not be null"); QString message(layout()->format(rEvent)); #if defined(Q_OS_WIN32) || defined(Q_WS_WIN) #if (QT_VERSION < 0x050000) QT_WA({ OutputDebugStringW(reinterpret_cast(message.utf16())); }, { OutputDebugStringA(message.toLocal8Bit().data()); }); #else OutputDebugStringW(reinterpret_cast(message.utf16())); #endif #else fprintf(stderr, "%s", message.toLocal8Bit().data()); fflush(stderr); #endif } void DebugAppender::asyncAppend(const LoggingEvent &rEvent) { // Q_ASSERT_X(, "DebugAppender::asyncAppend()", "Lock must be held by caller"); Q_ASSERT_X(layout(), "DebugAppender::asyncAppend()", "Layout must not be null"); QString message(layout()->format(rEvent)); #if defined(Q_OS_WIN32) || defined(Q_WS_WIN) #if (QT_VERSION < 0x050000) QT_WA({ OutputDebugStringW(reinterpret_cast(message.utf16())); }, { OutputDebugStringA(message.toLocal8Bit().data()); }); #else OutputDebugStringW(reinterpret_cast(message.utf16())); #endif #else fprintf(stderr, "%s", message.toLocal8Bit().data()); fflush(stderr); #endif } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM QDebug DebugAppender::debug(QDebug &rDebug) const { QString layout_name; if (layout()) layout_name = layout()->name(); rDebug.nospace() << "DebugAppender(" << "name:" << name() << " " << "filter:" << firstFilter() << " " << "isactive:" << isActive() << " " << "isclosed:" << isClosed() << " " << "layout:" << layout_name << " " << "referencecount:" << referenceCount() << " " << "threshold:" << threshold().toString() << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM } // namspace Log4Qt ukui-interface/src/log4qt/log4qt/varia/listappender.h0000664000175000017500000001267015167726064021617 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: listappender.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_LISTAPPENDER_H #define LOG4QT_LISTAPPENDER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/appenderskeleton.h" #include "ukui-logmacros.h" #include #include #include "log4qt/loggingevent.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * \brief The class ListAppender appends logging events to a list for later * processing. * * \note All the functions declared in this class are thread-safe. * * \note The ownership and lifetime of objects of this class are managed. * See \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT ListAppender : public AppenderSkeleton { Q_OBJECT /*! * The property holds, if the Appender is used by a configurator. * * The default value is false for not being a configurator list. * * \sa configuratorList(), setConfiguratorList() */ Q_PROPERTY(bool configuratorList READ configuratorList WRITE setConfiguratorList) /*! * The property holds the maximum count used by the appender. * * The default maximum count is -1 for unlimited. * * \sa maxCount(), setMaxCount() */ Q_PROPERTY(int maxCount READ maxCount WRITE setMaxCount) public: ListAppender(QObject *pParent = 0); virtual ~ListAppender(); private: ListAppender(const ListAppender &rOther); // Not implemented ListAppender &operator=(const ListAppender &rOther); // Not implemented public: /*! * Returns true, if the appender is used by a configurator. Otherweise it returns * false. * * \sa setConfiguratorList() */ bool configuratorList() const; QList list() const; int maxCount() const; /*! * Sets that the appender is used by a configurator. If set to true, the appender * will not be removed from a Logger when Logger::removeAllAppenders()is called. * This way the appender can collect events raised during the configuration process. * * \sa configuratorList(), BasicConfigurator, PropertyConfigurator, * ConfiguratorHelper::configureError() */ void setConfiguratorList(bool isConfiguratorList); void setMaxCount(int n); QList clearList(); virtual bool requiresLayout() const; protected: virtual void append(const LoggingEvent &rEvent); virtual void asyncAppend(const LoggingEvent &rEvent); #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream * \a rDebug and returns the stream. * * * %ListAppender(name:"LA" count:1 filter:0x41fa488 isactive:true * isclosed:false maxcount:170 referencecount:1 * threshold:"TRACE_SET") * * \sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const; #endif // QT_NO_DEBUG_STREAM /*! * Ensures that the count of events is less or equal then the maxium * count. If the list contains too many items, items are deleted from * the begin of the list. */ void ensureMaxCount(); private: volatile bool mConfiguratorList; QList mList; volatile int mMaxCount; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline bool ListAppender::configuratorList() const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe return mConfiguratorList; } inline int ListAppender::maxCount() const { return mMaxCount; } inline void ListAppender::setConfiguratorList(bool isConfiguratorList) { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe mConfiguratorList = isConfiguratorList; } inline bool ListAppender::requiresLayout() const { return false; } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::ListAppender, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_LISTAPPENDER_H ukui-interface/src/log4qt/log4qt/varia/levelmatchfilter.h0000664000175000017500000001016115167726064022450 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: levelmatchfilter.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_LEVELMATCHFILTER_H #define LOG4QT_LEVELMATCHFILTER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/spi/filter.h" #include "ukui-logmacros.h" #include "log4qt/level.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * \brief The class LevelMatchFilter allows logging events with a specified * level. * * \note The ownership and lifetime of objects of this class are managed. * See \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT LevelMatchFilter : public Filter { Q_OBJECT /*! * The property holds if an event is accpeted on a match. * * The default is true. * * \sa acceptOnMatch(), setAcceptOnMatch() */ Q_PROPERTY(bool acceptOnMatch READ acceptOnMatch WRITE setAcceptOnMatch) /*! * The property holds the level to match for this filter. * * The default is Level::NULL_INT. * * \sa levelToMatch(), setLevelToMatch() */ Q_PROPERTY(Level levelToMatch READ levelToMatch WRITE setLevelToMatch) public: LevelMatchFilter(QObject *pParent = 0); // LevelMatchFilter(const LevelMatchFilter &rOther); // Use compiler default // virtual ~LevelMatchFilter(); // Use compiler default // LevelMatchFilter &operator=(const LevelMatchFilter &rOther); // Use compiler default bool acceptOnMatch() const; Level levelToMatch() const; void setAcceptOnMatch(bool accept); void setLevelToMatch(Level level); virtual Decision decide(const LoggingEvent &rEvent) const; protected: #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream \a rDebug * and returns the stream. * * * %LevelMatchFilter(acceptonmatch:true leveltomatch:"WARN" * next:Log4Qt::DenyAllFilter(0x3bce3a8) * referencecount:1 ) * * \sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const; #endif // QT_NO_DEBUG_STREAM private: bool mAcceptOnMatch; Level mLevelToMatch; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline bool LevelMatchFilter::acceptOnMatch() const { return mAcceptOnMatch; } inline Level LevelMatchFilter::levelToMatch() const { return mLevelToMatch; } inline void LevelMatchFilter::setAcceptOnMatch(bool accept) { mAcceptOnMatch = accept; } inline void LevelMatchFilter::setLevelToMatch(Level level) { mLevelToMatch = level; } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::LevelMatchFilter, Q_MOVABLE_TYPE); // Use default #endif // LOG4QT_LEVELMATCHFILTER_H ukui-interface/src/log4qt/log4qt/varia/stringmatchfilter.h0000664000175000017500000001021215167726064022644 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: stringmatchfilter.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_STRINGMATCHFILTER_H #define LOG4QT_STRINGMATCHFILTER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/spi/filter.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * \brief The class StringMatchFilter allows logging events with a * specified level. * * \note The ownership and lifetime of objects of this class are managed. * See \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT StringMatchFilter : public Filter { Q_OBJECT /*! * The property holds if an event is accpeted on a match. * * The default is true. * * \sa acceptOnMatch(), acceptOnMatch() */ Q_PROPERTY(bool acceptOnMatch READ acceptOnMatch WRITE setAcceptOnMatch) /*! * The property holds the string to match for this filter. * * \sa stringToMatch(), setStringToMatch() */ Q_PROPERTY(QString stringToMatch READ stringToMatch WRITE setStringToMatch) public: StringMatchFilter(QObject *pParent = 0); // StringMatchFilter(const StringMatchFilter &rOther); // Use compiler default // virtual ~StringMatchFilter(); // Use compiler default // StringMatchFilter &operator=(const StringMatchFilter &rOther); // Use compiler default bool acceptOnMatch() const; QString stringToMatch() const; void setAcceptOnMatch(bool accept); void setStringToMatch(const QString &rString); virtual Decision decide(const LoggingEvent &rEvent) const; protected: #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream * \a rDebug and returns the stream. * * * %StringMatchFilter(acceptonmatch:true referencecount:1 * stringtomatch:"LDAP_STRONG_AUTH_REQUIRED" * next:Log4Qt::LevelMatchFilter(0x3bdd960) ) * * \sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const; #endif // QT_NO_DEBUG_STREAM private: bool mAcceptOnMatch; QString mStringToMatch; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline bool StringMatchFilter::acceptOnMatch() const { return mAcceptOnMatch; } inline QString StringMatchFilter::stringToMatch() const { return mStringToMatch; } inline void StringMatchFilter::setAcceptOnMatch(bool accept) { mAcceptOnMatch = accept; } inline void StringMatchFilter::setStringToMatch(const QString &rString) { mStringToMatch = rString; } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::StringMatchFilter, Q_MOVABLE_TYPE); // Use default #endif // LOG4QT_STRINGMATCHFILTER_H ukui-interface/src/log4qt/log4qt/varia/debugappender.h0000664000175000017500000001015715167726064021730 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: debugappender.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_DEBUGAPPENDER_H #define LOG4QT_DEBUGAPPENDER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/appenderskeleton.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * \brief The class DebugAppender appends logging events to the platform * specific debug output. * * A DebugAppender appends to the Debugger on Windows and to stderr on all * other systems. * * \note All the functions declared in this class are thread-safe. * * \note The ownership and lifetime of objects of this class are managed. * See \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT DebugAppender : public AppenderSkeleton { Q_OBJECT public: /*! * Creates a DebugAppender. */ DebugAppender(QObject *pParent = 0); /*! * Creates a DebugAppender with the specified layout \a pLayout */ DebugAppender(Layout *pLayout, QObject *pParent = 0); // virtual ~DebugAppender(); // Use compiler default private: DebugAppender(const DebugAppender &rOther); // Not implemented DebugAppender &operator=(const DebugAppender &rOther); // Not implemented public: /*! * The DebugAppended requires a layout. The function returns true. * * \sa setLayout() */ virtual bool requiresLayout() const; protected: /*! * Appends the specified logging event \a rEvent to the debug output. * The output is formatted using the appender's layout. * * The method is called by the AppenderSkeleton::doAppend() after it * the entry conditions have been tested and it has been found that the * logging event needs to be appended. * * \sa setLayout(), AppenderSkeleton::doAppend(), checkEntryConditions() */ virtual void append(const LoggingEvent &rEvent); virtual void asyncAppend(const LoggingEvent &rEvent); #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream \a rDebug * and returns the stream. * * * %DebugAppender(name:"DA" filter:0x3bee6b8 isactive:true isclosed:false * layout:"SL" referencecount:1 threshold:"NULL") * * \sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const; #endif // QT_NO_DEBUG_STREAM }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline DebugAppender::DebugAppender(QObject *pParent) : AppenderSkeleton(pParent) {} } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::DebugAppender, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_DEBUGAPPENDER_H ukui-interface/src/log4qt/log4qt/varia/stringmatchfilter.cpp0000664000175000017500000000547715167726064023220 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: stringmatchfilter.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/varia/stringmatchfilter.h" #include #include "log4qt/loggingevent.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: Filter **************************************************************************/ StringMatchFilter::StringMatchFilter(QObject *pParent) : Filter(pParent), mAcceptOnMatch(true), mStringToMatch() {} Filter::Decision StringMatchFilter::decide(const LoggingEvent &rEvent) const { if (rEvent.message().isEmpty() || mStringToMatch.isEmpty() || rEvent.message().indexOf(mStringToMatch) < 0) return Filter::NEUTRAL; if (mAcceptOnMatch) return Filter::ACCEPT; else return Filter::DENY; } #ifndef QT_NO_DEBUG_STREAM QDebug StringMatchFilter::debug(QDebug &rDebug) const { rDebug.nospace() << "StringMatchFilter(" << "acceptonmatch:" << mAcceptOnMatch << " " << "referencecount:" << referenceCount() << " " << "stringtomatch:" << mStringToMatch << " " << "next:" << next() << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/varia/levelmatchfilter.cpp0000664000175000017500000000544215167726064023011 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: levelmatchfilter.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/varia/levelmatchfilter.h" #include #include "log4qt/loggingevent.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: Filter **************************************************************************/ LevelMatchFilter::LevelMatchFilter(QObject *pParent) : Filter(pParent), mAcceptOnMatch(true), mLevelToMatch(Level::NULL_INT) {} Filter::Decision LevelMatchFilter::decide(const LoggingEvent &rEvent) const { if (mLevelToMatch == Level::NULL_INT || rEvent.level() != mLevelToMatch) return Filter::NEUTRAL; if (mAcceptOnMatch) return Filter::ACCEPT; else return Filter::DENY; } #ifndef QT_NO_DEBUG_STREAM QDebug LevelMatchFilter::debug(QDebug &rDebug) const { rDebug.nospace() << "LevelMatchFilter(" << "acceptonmatch:" << mAcceptOnMatch << " " << "leveltomatch:" << mLevelToMatch.toString() << " " << "next:" << next() << "referencecount:" << referenceCount() << " " << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/varia/levelrangefilter.h0000664000175000017500000001104415167726064022451 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: levelrangefilter.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_LEVELRANGEFILTER_H #define LOG4QT_LEVELRANGEFILTER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/spi/filter.h" #include "ukui-logmacros.h" #include "log4qt/level.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * \brief The class LevelMatchFilter allows logging events with levels in a * specified range. * * \note The ownership and lifetime of objects of this class are managed. * See \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT LevelRangeFilter : public Filter { Q_OBJECT /*! * The property holds if an event is accpeted on a match. * * The default is true. * * \sa acceptOnMatch(), acceptOnMatch() */ Q_PROPERTY(bool acceptOnMatch READ acceptOnMatch WRITE setAcceptOnMatch) /*! * The property holds the maximum level of the range for this filter. * * The default is Level::OFF_INT. * * \sa levelMax(), setLevelMax() */ Q_PROPERTY(Level levelMax READ levelMax WRITE setLevelMax) /*! * The property holds the minimum level of the range for this filter. * * The default is Level::NULL_INT. * * \sa levelMin(), setLevelMin() */ Q_PROPERTY(Level levelMin READ levelMin WRITE setLevelMin) public: LevelRangeFilter(QObject *pParent = 0); // LevelRangeFilter(const LevelRangeFilter &rOther); // Use compiler default // virtual ~LevelRangeFilter(); // Use compiler default // LevelRangeFilter &operator=(const LevelRangeFilter &rOther); // Use compiler default bool acceptOnMatch() const; Level levelMax() const; Level levelMin() const; void setAcceptOnMatch(bool accept); void setLevelMax(Level level); void setLevelMin(Level level); virtual Decision decide(const LoggingEvent &rEvent) const; protected: /*! * Writes all object member variables to the given debug stream \a rDebug * and returns the stream. * * * %LevelRangeFilter(acceptonmatch:true levelmin:"ERROR" levelmax:"FATAL" * next:Log4Qt::LevelMatchFilter(0x3bcd960) * referencecount:1 ) * * \sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const; private: bool mAcceptOnMatch; Level mLevelMin; Level mLevelMax; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline bool LevelRangeFilter::acceptOnMatch() const { return mAcceptOnMatch; } inline Level LevelRangeFilter::levelMax() const { return mLevelMax; } inline Level LevelRangeFilter::levelMin() const { return mLevelMin; } inline void LevelRangeFilter::setAcceptOnMatch(bool accept) { mAcceptOnMatch = accept; } inline void LevelRangeFilter::setLevelMax(Level level) { mLevelMax = level; } inline void LevelRangeFilter::setLevelMin(Level level) { mLevelMin = level; } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::LevelRangeFilter, Q_MOVABLE_TYPE); // Use default #endif // LOG4QT_LEVELRANGEFILTER_H ukui-interface/src/log4qt/log4qt/varia/denyallfilter.cpp0000664000175000017500000000427015167726064022313 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: denyallfilter.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/varia/denyallfilter.h" #include namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: Filter **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM QDebug DenyAllFilter::debug(QDebug &rDebug) const { rDebug.nospace() << "DenyAllFilter(" << "next:" << next() << "referencecount:" << referenceCount() << " " << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/varia/nullappender.h0000664000175000017500000000602015167726064021606 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: nullappender.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_NULLAPPENDER_H #define LOG4QT_NULLAPPENDER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/appenderskeleton.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * \brief The class NullAppender ignores all requests to append. * * \note All the functions declared in this class are thread-safe. * * \note The ownership and lifetime of objects of this class are managed. See * \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT NullAppender : public AppenderSkeleton { Q_OBJECT public: NullAppender(QObject *pParent = 0); virtual ~NullAppender(); private: NullAppender(const NullAppender &rOther); // Not implemented NullAppender &operator=(const NullAppender &rOther); // Not implemented public: virtual bool requiresLayout() const; protected: virtual void append(const LoggingEvent &rEvent); virtual void asyncAppend(const LoggingEvent &rEvent); #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream \a rDebug and * returns the stream. * * * %NullAppender() * * \sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const; #endif // QT_NO_DEBUG_STREAM }; /****************************************************************************** * Operators, Helper ******************************************************************************/ /****************************************************************************** * Inline ******************************************************************************/ inline bool NullAppender::requiresLayout() const { return false; } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::NullAppender, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_NULLAPPENDER_H ukui-interface/src/log4qt/log4qt/varia/levelrangefilter.cpp0000664000175000017500000000554315167726064023013 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: levelrangefilter.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/varia/levelrangefilter.h" #include #include "log4qt/loggingevent.h" namespace Log4Qt { /****************************************************************************** * Declarations ******************************************************************************/ /****************************************************************************** * C helper functions ******************************************************************************/ /****************************************************************************** * Class implementation: Filter ******************************************************************************/ LevelRangeFilter::LevelRangeFilter(QObject *pParent) : Filter(pParent), mAcceptOnMatch(true), mLevelMin(Level::NULL_INT), mLevelMax(Level::OFF_INT) {} Filter::Decision LevelRangeFilter::decide(const LoggingEvent &rEvent) const { if (rEvent.level() < mLevelMin) return Filter::DENY; if (rEvent.level() > mLevelMax) return Filter::DENY; if (mAcceptOnMatch) return Filter::ACCEPT; else return Filter::NEUTRAL; } #ifndef QT_NO_DEBUG_STREAM QDebug LevelRangeFilter::debug(QDebug &rDebug) const { rDebug.nospace() << "LevelRangeFilter(" << "acceptonmatch:" << mAcceptOnMatch << " " << "levelmin:" << mLevelMin.toString() << " " << "levelmax:" << mLevelMax.toString() << " " << "next:" << next() << "referencecount:" << referenceCount() << " " << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM /****************************************************************************** * Implementation: Operators, Helper ******************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/varia/listappender.cpp0000664000175000017500000001000515167726064022140 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: listappender.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/varia/listappender.h" #include namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: ListAppender **************************************************************************/ ListAppender::ListAppender(QObject *pParent) : AppenderSkeleton(pParent), mConfiguratorList(false), mList(), mMaxCount(0) { } ListAppender::~ListAppender() { } QList ListAppender::list() const { QMutexLocker locker(&mObjectGuard); return mList; } void ListAppender::setMaxCount(int n) { QMutexLocker locker(&mObjectGuard); if (n < 0) { logger()->warn("Attempt to set maximum count for appender '%1' to %2. Using zero instead", name(), n); n = 0; } mMaxCount = n; ensureMaxCount(); } QList ListAppender::clearList() { QMutexLocker locker(&mObjectGuard); QList result = mList; mList.clear(); return result; } // bool ListAppender::requiresLayout() const; void ListAppender::append(const LoggingEvent &rEvent) { // Q_ASSERT_X(, "ListAppender::append()", "Lock must be held by caller") if ((mMaxCount <= 0) || (mList.size() < mMaxCount)) mList << rEvent; } void ListAppender::asyncAppend(const LoggingEvent &rEvent) { // Q_ASSERT_X(, "ListAppender::asyncAppend()", "Lock must be held by caller") if ((mMaxCount <= 0) || (mList.size() < mMaxCount)) mList << rEvent; } #ifndef QT_NO_DEBUG_STREAM QDebug ListAppender::debug(QDebug &rDebug) const { rDebug.nospace() << "ListAppender(" << "name:" << name() << " " << "count:" << list().count() << " " << "filter:" << firstFilter() << " " << "isactive:" << isActive() << " " << "isclosed:" << isClosed() << " " << "maxcount:" << maxCount() << " " << "referencecount:" << referenceCount() << " " << "threshold:" << threshold().toString() << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM void ListAppender::ensureMaxCount() { // Q_ASSERT_X(, "ListAppender::ensureMaxCount()", "Lock must be held by caller") if (mMaxCount <= 0) return; while (mList.size() > mMaxCount) mList.removeFirst(); } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/log4qt.pri0000664000175000017500000000676715167726064017612 0ustar fengfeng# ******************************************************************************* # # package: Log4Qt # file: log4qt.pri # created: September 2007 # author: Martin Heinrich # # # Copyright 2007 Martin Heinrich # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # ******************************************************************************* INCLUDEPATH += $$PWD/.. DEPENDPATH += $$PWD/.. HEADERS += \ $$PWD/appender.h \ $$PWD/appenderskeleton.h \ $$PWD/basicconfigurator.h \ $$PWD/consoleappender.h \ $$PWD/dailyrollingfileappender.h \ $$PWD/fileappender.h \ $$PWD/helpers/classlogger.h \ $$PWD/helpers/configuratorhelper.h \ $$PWD/helpers/datetime.h \ $$PWD/helpers/factory.h \ $$PWD/helpers/initialisationhelper.h \ $$PWD/helpers/logerror.h \ $$PWD/helpers/logobject.h \ $$PWD/helpers/logobjectptr.h \ $$PWD/helpers/optionconverter.h \ $$PWD/helpers/patternformatter.h \ $$PWD/helpers/properties.h \ $$PWD/helpers/asyncdispatcher.h \ $$PWD/hierarchy.h \ $$PWD/layout.h \ $$PWD/level.h \ $$PWD/log4qt.h \ $$PWD/logger.h \ $$PWD/loggerrepository.h \ $$PWD/loggingevent.h \ $$PWD/logmanager.h \ $$PWD/mdc.h \ $$PWD/ndc.h \ $$PWD/patternlayout.h \ $$PWD/propertyconfigurator.h \ $$PWD/rollingfileappender.h \ $$PWD/simplelayout.h \ $$PWD/spi/filter.h \ $$PWD/ttcclayout.h \ $$PWD/writerappender.h \ $$PWD/varia/debugappender.h \ $$PWD/varia/denyallfilter.h \ $$PWD/varia/nullappender.h \ $$PWD/varia/levelmatchfilter.h \ $$PWD/varia/levelrangefilter.h \ $$PWD/varia/listappender.h \ $$PWD/varia/stringmatchfilter.h SOURCES += \ $$PWD/appenderskeleton.cpp \ $$PWD/basicconfigurator.cpp \ $$PWD/consoleappender.cpp \ $$PWD/dailyrollingfileappender.cpp \ $$PWD/fileappender.cpp \ $$PWD/helpers/classlogger.cpp \ $$PWD/helpers/configuratorhelper.cpp \ $$PWD/helpers/datetime.cpp \ $$PWD/helpers/factory.cpp \ $$PWD/helpers/initialisationhelper.cpp \ $$PWD/helpers/logerror.cpp \ $$PWD/helpers/logobject.cpp \ $$PWD/helpers/logobjectptr.cpp \ $$PWD/helpers/optionconverter.cpp \ $$PWD/helpers/patternformatter.cpp \ $$PWD/helpers/properties.cpp \ $$PWD/helpers/asyncdispatcher.cpp \ $$PWD/hierarchy.cpp \ $$PWD/layout.cpp \ $$PWD/level.cpp \ $$PWD/log4qt.cpp \ $$PWD/logger.cpp \ $$PWD/loggerrepository.cpp \ $$PWD/loggingevent.cpp \ $$PWD/logmanager.cpp \ $$PWD/mdc.cpp \ $$PWD/ndc.cpp \ $$PWD/patternlayout.cpp \ $$PWD/propertyconfigurator.cpp \ $$PWD/rollingfileappender.cpp \ $$PWD/simplelayout.cpp \ $$PWD/spi/filter.cpp \ $$PWD/ttcclayout.cpp \ $$PWD/writerappender.cpp \ $$PWD/varia/debugappender.cpp \ $$PWD/varia/denyallfilter.cpp \ $$PWD/varia/nullappender.cpp \ $$PWD/varia/levelmatchfilter.cpp \ $$PWD/varia/levelrangefilter.cpp \ $$PWD/varia/listappender.cpp \ $$PWD/varia/stringmatchfilter.cpp ukui-interface/src/log4qt/log4qt/fileappender.cpp0000664000175000017500000002175315167726076021021 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: fileappender.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/fileappender.h" #include #include #include #include #include #if QT_VERSION < 0x060000 #include #endif #include "log4qt/layout.h" #include "log4qt/loggingevent.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: FileAppender **************************************************************************/ FileAppender::FileAppender(QObject *pParent) : WriterAppender(pParent), mAppendFile(false), mBufferedIo(true), mFileName(), mpFile(0), mpTextStream(0) { } FileAppender::FileAppender(Layout *pLayout, const QString &rFileName, QObject *pParent) : WriterAppender(pLayout, pParent), mAppendFile(false), mBufferedIo(true), mFileName(rFileName), mpFile(0), mpTextStream(0) { } FileAppender::FileAppender(Layout *pLayout, const QString &rFileName, bool append, QObject *pParent) : WriterAppender(pLayout, pParent), mAppendFile(append), mBufferedIo(true), mFileName(rFileName), mpFile(0), mpTextStream(0) { } FileAppender::FileAppender(Layout *pLayout, const QString &rFileName, bool append, bool buffered, QObject *pParent) : WriterAppender(pLayout, pParent), mAppendFile(append), mBufferedIo(buffered), mFileName(rFileName), mpFile(0), mpTextStream(0) { } FileAppender::~FileAppender() { close(); } void FileAppender::activateOptions() { QMutexLocker locker(&mObjectGuard); if (mFileName.isEmpty()) { LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Activation of Appender '%1' that requires file and has no file set"), APPENDER_ACTIVATE_MISSING_FILE_ERROR); e << name(); logger()->error(e); return; } closeFile(); openFile(); WriterAppender::activateOptions(); } void FileAppender::close() { QMutexLocker locker(&mObjectGuard); if (isClosed()) return; WriterAppender::close(); closeFile(); } bool FileAppender::checkEntryConditions() const { // Q_ASSERT_X(, "FileAppender::checkEntryConditions()", "Lock must be held by caller") if (!mpFile || !mpTextStream) { LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Use of appender '%1' without open file"), APPENDER_NO_OPEN_FILE_ERROR); e << name(); logger()->error(e); return false; } return WriterAppender::checkEntryConditions(); } void FileAppender::closeFile() { // Q_ASSERT_X(, "FileAppender::closeFile()", "Lock must be held by caller") if (mpFile) logger()->debug("Closing file '%1' for appender '%2'", mpFile->fileName(), name()); setWriter(0); delete mpTextStream; mpTextStream = 0; delete mpFile; mpFile = 0; } #ifndef QT_NO_DEBUG_STREAM QDebug FileAppender::debug(QDebug &rDebug) const { QString layout_name; if (layout()) layout_name = layout()->name(); QString codec_name; #if QT_VERSION < 0x060000 if (encoding()) codec_name = QLatin1String(encoding()->name()); #else codec_name = QLatin1String(QStringConverter::nameForEncoding(encoding())); #endif rDebug.nospace() << "FileAppender(" << "name:" << name() << " " << "appendfile:" << appendFile() << " " << "bufferedio:" << bufferedIo() << " " << "encoding:" << codec_name << " " << "file:" << file() << " " << "filter:" << firstFilter() << " " << "immediateflush:" << immediateFlush() << " " << "isactive:" << isActive() << " " << "isclosed:" << isClosed() << " " << "layout:" << layout_name << " " << "referencecount:" << referenceCount() << " " << "threshold:" << threshold().toString() << " " << "writer:" << writer() << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM bool FileAppender::handleIoErrors() const { // Q_ASSERT_X(, "FileAppender::handleIoErrors()", "Lock must be held by caller") if (mpFile->error() == QFile::NoError) return false; LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Unable to write to file '%1' for appender '%2'"), APPENDER_WRITING_FILE_ERROR); e << mFileName << name(); e.addCausingError(LogError(mpFile->errorString(), mpFile->error())); logger()->error(e); return true; } void FileAppender::openFile() { Q_ASSERT_X(mpFile == 0 && mpTextStream == 0, "FileAppender::openFile()", "Opening file without closing previous file"); QFileInfo file_info(mFileName); QDir parent_dir = file_info.dir(); if (!parent_dir.exists()) { logger()->trace("Creating missing parent directory for file %1", mFileName); QString name = parent_dir.dirName(); parent_dir.cdUp(); parent_dir.mkdir(name); } mpFile = new QFile(mFileName); QFile::OpenMode mode = QIODevice::WriteOnly | QIODevice::Text; if (mAppendFile) mode |= QIODevice::Append; else mode |= QIODevice::Truncate; if (!mBufferedIo) mode |= QIODevice::Unbuffered; if (!mpFile->open(mode)) { LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Unable to open file '%1' for appender '%2'"), APPENDER_OPENING_FILE_ERROR); e << mFileName << name(); e.addCausingError(LogError(mpFile->errorString(), mpFile->error())); logger()->error(e); return; } mpTextStream = new QTextStream(mpFile); setWriter(mpTextStream); logger()->debug("Opened file '%1' for appender '%2'", mpFile->fileName(), name()); } bool FileAppender::removeFile(QFile &rFile) const { if (rFile.remove()) return true; LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Unable to remove file '%1' for appender '%2'"), APPENDER_REMOVE_FILE_ERROR); e << rFile.fileName() << name(); e.addCausingError(LogError(rFile.errorString(), rFile.error())); logger()->error(e); return false; } bool FileAppender::renameFile(QFile &rFile, const QString &rFileName) const { logger()->debug("Renaming file '%1' to '%2'", rFile.fileName(), rFileName); if (!rFileName.compare(rFile.fileName())) return true; if (rFile.rename(rFileName)) return true; LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Unable to rename file '%1' to '%2' for appender '%3'"), APPENDER_RENAMING_FILE_ERROR); e << rFile.fileName() << rFileName << name(); e.addCausingError(LogError(rFile.errorString(), rFile.error())); logger()->error(e); return false; } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/mdc.h0000664000175000017500000000644415167726064016570 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: mdc.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_MDC_H #define LOG4QT_MDC_H /****************************************************************************** * Dependencies ******************************************************************************/ #include #include #include #include "log4qt/log4qt.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * \brief The class MDC implements a mapped diagnostic context. * * \note All the functions declared in this class are thread-safe. */ class LIBUKUILOG4QT_EXPORT MDC { private: MDC(); MDC(const MDC &rOther); // Not implemented // virtual ~MDC(); // Use compiler default MDC &operator=(const MDC &rOther); // Not implemented public: static QString get(const QString &rKey); static QHash context(); /*! * Returns the MDC instance. */ static MDC *instance(); static void put(const QString &rKey, const QString &rValue); static void remove(const QString &rKey); private: static QHash *localData(); private: QThreadStorage< QHash * > mHash; }; /************************************************************************** * Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM /*! * \relates MDC * * Writes all object member variables to the given debug stream \a rDebug * and returns the stream. * * * %MDC(thread:"main" context:QHash(("login", "Peter")("database", "UAT")) ) * * \sa QDebug */ QDebug operator<<(QDebug debug, const MDC &rMDC); #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Inline **************************************************************************/ inline MDC::MDC() : mHash() {} inline void MDC::put(const QString &rKey, const QString &rValue) { localData()->insert(rKey, rValue); } inline void MDC::remove(const QString &rKey) { localData()->remove(rKey); } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::MDC, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_MDC_H ukui-interface/src/log4qt/log4qt/ndc.h0000664000175000017500000000641415167726064016566 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: ndc.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_NDC_H #define LOG4QT_NDC_H /****************************************************************************** * Dependencies ******************************************************************************/ #include #include #include #include "log4qt/log4qt.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * \brief The class NDC implements a nested diagnostic context. * * The method remove() is not required. QThreadStorage cleans up on thread * exit. * * \note All the functions declared in this class are thread-safe. */ class LIBUKUILOG4QT_EXPORT NDC { private: NDC(); NDC(const NDC &rOther); // Not implemented // virtual ~NDC(); // Use compiler default NDC &operator=(const NDC &rOther); // Not implemented public: static void clear(); // JAVA: static QStack cloneStack(); // JAVA: static QString get(); static int depth(); // JAVA: inherit(Stack stack) /*! * Returns the NDC instance. */ static NDC *instance(); static QString pop(); static void push(const QString &rMessage); // JAVA: static void remove(); // Not required static void setMaxDepth(int maxDepth); static QString peek(); private: QThreadStorage< QStack * > mStack; }; /****************************************************************************** * Operators, Helper ******************************************************************************/ #ifndef QT_NO_DEBUG_STREAM /*! * \relates NDC * * Writes all object member variables to the given debug stream \a rDebug and * returns the stream. * * * %NDC(thread:"main" peek:"i = 3" depth:4) * * \sa QDebug */ QDebug operator<<(QDebug debug, const NDC &rNDC); #endif // QT_NO_DEBUG_STREAM /****************************************************************************** * Inline ******************************************************************************/ inline NDC::NDC() : mStack() {} } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::NDC, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_NDC_H ukui-interface/src/log4qt/log4qt/appenderskeleton.cpp0000664000175000017500000001604115167726076021720 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: appenderskeleton.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/appenderskeleton.h" #include #include "log4qt/layout.h" #include "log4qt/loggingevent.h" #include "log4qt/logmanager.h" #include "log4qt/spi/filter.h" namespace Log4Qt { /************************************************************************** * Declarations ***************************************************************************/ /*! * \brief The class RecursionGuardLocker controls a boolean flag. * * It is a helper class to control a boolean flag. The class sets the flag * on creation and resets it on destruction. */ class RecursionGuardLocker { public: RecursionGuardLocker(bool *pGuard); ~RecursionGuardLocker(); private: RecursionGuardLocker(const RecursionGuardLocker &rOther); // Not implemented RecursionGuardLocker &operator=(const RecursionGuardLocker &rOther); // Not implemented private: bool *mpGuard; }; /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: RecursionGuardLocker ***************************************************************************/ inline RecursionGuardLocker::RecursionGuardLocker(bool *pGuard) { Q_ASSERT_X(pGuard != 0, "RecursionGuardLocker::RecursionGuardLocker()", "Pointer to guard bool must not be null"); mpGuard = pGuard; *mpGuard = true; } inline RecursionGuardLocker::~RecursionGuardLocker() { *mpGuard = false; }; /************************************************************************** * Class implementation: AppenderSkeleton **************************************************************************/ AppenderSkeleton::AppenderSkeleton(QObject *pParent) : Appender(pParent), #if QT_VERSION < 0x050E00 mObjectGuard(QMutex::Recursive), // Recursive for doAppend() #endif mAppendRecursionGuard(false), mIsActive(true), mIsClosed(false), mpLayout(0), mThreshold(Level::NULL_INT), mpHeadFilter(0), mpTailFilter(0) { } AppenderSkeleton::AppenderSkeleton(const bool isActive, QObject *pParent) : Appender(pParent), #if QT_VERSION < 0x050E00 mObjectGuard(QMutex::Recursive), // Recursive for doAppend() #endif mAppendRecursionGuard(false), mIsActive(isActive), mIsClosed(false), mpLayout(0), mThreshold(Level::NULL_INT), mpHeadFilter(0), mpTailFilter(0) { } void AppenderSkeleton::activateOptions() { QMutexLocker locker(&mObjectGuard); if (requiresLayout() && !layout()) { LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Activation of appender '%1' that requires layout and has no layout set"), APPENDER_ACTIVATE_MISSING_LAYOUT_ERROR); e << name(); logger()->error(e); return; } mIsActive = true; } void AppenderSkeleton::addFilter(Filter *pFilter) { if(!pFilter) { logger()->warn("Adding null Filter to Appender '%1'", name()); return; } QMutexLocker locker(&mObjectGuard); mpTailFilter = pFilter; if (mpHeadFilter) mpHeadFilter->setNext(pFilter); else mpHeadFilter = pFilter; } void AppenderSkeleton::clearFilters() { QMutexLocker locker(&mObjectGuard); mpTailFilter = 0; mpHeadFilter = 0; } void AppenderSkeleton::close() { QMutexLocker locker(&mObjectGuard); mIsClosed = true; mIsActive = false; } void AppenderSkeleton::doAppend(const LoggingEvent &rEvent) { // The mutex serialises concurrent access from multiple threads. // - e.g. two threads using the same logger // - e.g. two threads using different logger with the same appender // // A call from the same thread will pass the mutex (QMutex::Recursive) // and get to the recursion guard. The recursion guard blocks recursive // invocation and prevents a possible endless loop. // - e.g. an appender logs an error with a logger that uses it QMutexLocker locker(&mObjectGuard); if (mAppendRecursionGuard) return; RecursionGuardLocker recursion_locker(&mAppendRecursionGuard); if (!checkEntryConditions()) return; if (!isAsSevereAsThreshold(rEvent.level())) return; Filter *p_filter = mpHeadFilter; while(p_filter) { Filter::Decision decision = p_filter->decide(rEvent); if (decision == Filter::ACCEPT) break; else if (decision == Filter::DENY) return; else p_filter = p_filter->next(); } append(rEvent); } bool AppenderSkeleton::checkEntryConditions() const { // Q_ASSERT_X(, "WriterAppender::checkEntryConditions()", "Lock must be held by caller") if (!isActive()) { LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Use of non activated appender '%1'"), APPENDER_NOT_ACTIVATED_ERROR); e << name(); logger()->error(e); return false; } if (isClosed()) { LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Use of closed appender '%1'"), APPENDER_CLOSED_ERROR); e << name(); logger()->error(e); return false; } if (requiresLayout() && !layout()) { LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Use of appender '%1' that requires layout and has no layout set"), APPENDER_USE_MISSING_LAYOUT_ERROR); e << name(); logger()->error(e); return false; } return true; } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/patternlayout.h0000664000175000017500000001117015167726064020730 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: patternlayout.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_PATTERNLAYOUT_H #define LOG4QT_PATTERNLAYOUT_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/layout.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { class PatternFormatter; /*! * \brief The class PatternLayout outputs a logging event based on a * pattern string. * * \note The ownership and lifetime of objects of this class are managed. * See \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT PatternLayout : public Layout { Q_OBJECT /*! * The property holds the conversion pattern used by the appender. * * The default is "%m%n". * * \sa conversionPattern(), setConversionPattern() */ Q_PROPERTY(QString conversionPattern READ conversionPattern WRITE setConversionPattern) public: /*! * The enum ConversionPattern defines constants for pattern strings. * * \sa setConversionPattern(ConversionPattern); */ enum ConversionPattern { /*! The default conversion pattern string is "%m,%n". */ DEFAULT_CONVERSION_PATTERN, /*! * The ttcc conversion pattern string is * "%r [%t] %p %c %x - %m%n". */ TTCC_CONVERSION_PATTERN, }; Q_ENUMS(ConversionPattern) PatternLayout(QObject *pParent = 0); PatternLayout(const QString &rPattern, QObject *pParent = 0); /*! * Creates a PatternLayout with the conversion pattern value specified * by the \a conversionPattern constant. */ PatternLayout(ConversionPattern conversionPattern, QObject *pParent = 0); virtual ~PatternLayout(); private: PatternLayout(const PatternLayout &rOther); // Not implemented PatternLayout &operator=(const PatternLayout &rOther); // Not implemented public: QString conversionPattern() const; void setConversionPattern(const QString &rPattern); /*! * Sets the conversion pattern to the value specified by the * \a conversionPattern constant. */ void setConversionPattern(ConversionPattern conversionPattern); virtual QString format(const LoggingEvent &rEvent); protected: #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream * \a rDebug and returns the stream. * * * %PatternLayout(name:"PL" pattern:"%r [%t] %p %c %x - %m%n" * "referencecount:3") * * \sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const; #endif // QT_NO_DEBUG_STREAM private: void updatePatternFormatter(); private: QString mPattern; PatternFormatter *mpPatternFormatter; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline QString PatternLayout::conversionPattern() const { return PatternLayout::mPattern; } inline void PatternLayout::setConversionPattern(const QString &rPattern) { mPattern = rPattern; updatePatternFormatter(); } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::PatternLayout, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_PATTERNLAYOUT_H ukui-interface/src/log4qt/log4qt/writerappender.cpp0000664000175000017500000002101215167726076021402 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: writerappender.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/writerappender.h" #include #if QT_VERSION < 0x060000 #include #endif #include #include #include #include "log4qt/layout.h" #include "log4qt/loggingevent.h" #include "log4qt/helpers/asyncdispatcher.h" extern pid_t g_MainProcPid; namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: WriterAppender **************************************************************************/ WriterAppender::WriterAppender(QObject *pParent) : AppenderSkeleton(false, pParent), #if QT_VERSION < 0x060000 mEncoding(nullptr), #else mEncoding(QStringConverter::Encoding::Utf8), #endif mpWriter(0), mImmediateFlush(true) { } WriterAppender::WriterAppender(Layout *pLayout, QObject *pParent) : AppenderSkeleton(false, pParent), #if QT_VERSION < 0x060000 mEncoding(nullptr), #else mEncoding(QStringConverter::Encoding::System), #endif mpWriter(0), mImmediateFlush(true) { setLayout(pLayout); } WriterAppender::WriterAppender(Layout *pLayout, QTextStream *pTextStream, QObject *pParent) : AppenderSkeleton(false, pParent), #if QT_VERSION < 0x060000 mEncoding(nullptr), #else mEncoding(QStringConverter::Encoding::System), #endif mpWriter(pTextStream), mImmediateFlush(true) { setLayout(pLayout); } WriterAppender::~WriterAppender() { close(); } #if QT_VERSION < 0x060000 void WriterAppender::setEncoding(QTextCodec *encoding) #else void WriterAppender::setEncoding(QStringConverter::Encoding encoding) #endif { QMutexLocker locker(&mObjectGuard); if (mEncoding == encoding) return; mEncoding = encoding; if (mpWriter != nullptr) { #if QT_VERSION < 0x060000 if (mEncoding) mpWriter->setCodec(mEncoding); else mpWriter->setCodec(QTextCodec::codecForLocale()); #else mpWriter->setEncoding(mEncoding); #endif } } void WriterAppender::setWriter(QTextStream *pTextStream) { QMutexLocker locker(&mObjectGuard); closeWriter(); mpWriter = pTextStream; #if QT_VERSION < 0x060000 if ((mEncoding != nullptr) && (mpWriter != nullptr)) mpWriter->setCodec(mEncoding); #else if (mpWriter != nullptr) mpWriter->setEncoding(mEncoding); #endif writeHeader(); } void WriterAppender::activateOptions() { QMutexLocker locker(&mObjectGuard); if (!writer()) { LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Activation of Appender '%1' that requires writer and has no writer set"), APPENDER_ACTIVATE_MISSING_WRITER_ERROR); e << name(); logger()->error(e); return; } AppenderSkeleton::activateOptions(); } void WriterAppender::close() { QMutexLocker locker(&mObjectGuard); if (isClosed()) return; closeInternal(); AppenderSkeleton::close(); closeWriter(); } void WriterAppender::closeInternal() { if (isClosed()) return; } bool WriterAppender::requiresLayout() const { return true; } void WriterAppender::append(const LoggingEvent &rEvent) { // Q_ASSERT_X(, "WriterAppender::append()", "Lock must be held by caller"); Q_ASSERT_X(layout(), "WriterAppender::append()", "Layout must not be null"); QString message(layout()->format(rEvent)); if (!mpWriter) return; *mpWriter << message; if (handleIoErrors()) return; if (immediateFlush()) { mpWriter->flush(); if (handleIoErrors()) return; } } void WriterAppender::asyncAppend(const LoggingEvent &rEvent) { // Q_ASSERT_X(, "WriterAppender::asyncAppend()", "Lock must be held by caller"); Q_ASSERT_X(layout(), "WriterAppender::asyncAppend()", "Layout must not be null"); QString message(layout()->format(rEvent)); if (!mpWriter) return; *mpWriter << message; if (handleIoErrors()) return; if (immediateFlush()) { mpWriter->flush(); if (handleIoErrors()) return; } } bool WriterAppender::checkEntryConditions() const { // Q_ASSERT_X(, "WriterAppender::checkEntryConditions()", "Lock must be held by caller") if (!writer()) { LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Use of appender '%1' without a writer set"), APPENDER_USE_MISSING_WRITER_ERROR); e << name(); logger()->error(e); return false; } return AppenderSkeleton::checkEntryConditions(); } void WriterAppender::closeWriter() { // Q_ASSERT_X(, "WriterAppender::closeWriter()", "Lock must be held by caller") if (!mpWriter) return; writeFooter(); mpWriter = 0; } #ifndef QT_NO_DEBUG_STREAM QDebug WriterAppender::debug(QDebug &rDebug) const { QString layout_name; if (layout()) layout_name = layout()->name(); QString codec_name; #if QT_VERSION < 0x060000 if (encoding()) codec_name = QLatin1String(encoding()->name()); #else codec_name = QLatin1String(QStringConverter::nameForEncoding(encoding())); #endif rDebug.nospace() << "WriterAppender(" << "name:" << name() << " " << "encoding:" << codec_name << " " << "filter:" << firstFilter() << "immediateFlush:" << immediateFlush() << "isactive:" << isActive() << "isclosed:" << isClosed() << "layout:" << layout_name << "referencecount:" << referenceCount() << " " << "threshold:" << threshold().toString() << "writer:" << writer() << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM bool WriterAppender::handleIoErrors() const { return false; } void WriterAppender::writeFooter() const { // Q_ASSERT_X(, "WriterAppender::writeFooter()", "Lock must be held by caller") if (!layout() || !mpWriter) return; QString footer = layout()->footer(); if (footer.isEmpty()) return; *mpWriter << footer << Layout::endOfLine(); if (handleIoErrors()) return; } void WriterAppender::writeHeader() const { // Q_ASSERT_X(, "WriterAppender::writeHeader()", "Lock must be held by caller") if (!layout() || !mpWriter) return; QString header = layout()->header(); if (header.isEmpty()) return; *mpWriter << header << Layout::endOfLine(); if (handleIoErrors()) return; } /****************************************************************************** * Implementation: Operators, Helper ******************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/loggerrepository.cpp0000664000175000017500000000416215167726064021772 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: loggerrepository.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/loggerrepository.h" #include namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: LoggerRepository **************************************************************************/ /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const LoggerRepository &rLoggerRepository) { return rLoggerRepository.debug(debug); } #endif // QT_NO_DEBUG_STREAM } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/hierarchy.cpp0000664000175000017500000001271715167726064020336 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: hierarchy.cpp * created: September 2007 * author: Martin Heinrich * * * changes: Sep 2008, Martin Heinrich: * - Fixed problem in Qt 4.4 where QReadWriteLock is by default * non-recursive. * * * Copyright 2007 - 2008 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/hierarchy.h" #include #include "log4qt/logger.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ LOG4QT_DECLARE_STATIC_LOGGER(static_logger, Log4Qt::LoggerRepository) /************************************************************************** * Class implementation: Hierarchy **************************************************************************/ Hierarchy::Hierarchy() : #if QT_VERSION < QT_VERSION_CHECK(4, 4, 0) mObjectGuard(), #else mObjectGuard(QReadWriteLock::Recursive), #endif mLoggers(), mThreshold(Level::NULL_INT), mpRootLogger(logger(QString())) { // Store root logger to allow rootLogger() to be const } Hierarchy::~Hierarchy() { static_logger()->warn("Unexpected destruction of Hierarchy"); // QWriteLocker locker(&mObjectGuard); // // resetConfiguration(); // clear(); // delete mpRootLogger; } bool Hierarchy::exists(const QString &rName) const { QReadLocker locker(&mObjectGuard); return mLoggers.contains(rName); } Logger *Hierarchy::logger(const QString &rName) { QWriteLocker locker(&mObjectGuard); return createLogger(rName); } QList Hierarchy::loggers() const { QReadLocker locker(&mObjectGuard); return mLoggers.values(); } void Hierarchy::setThreshold(const QString &rThreshold) { setThreshold(Level::fromString(rThreshold)); } void Hierarchy::resetConfiguration() { QWriteLocker locker(&mObjectGuard); // Reset all loggers. // Leave log, qt and root logger to the last to allow debugging of shutdown. Logger *p_logging_logger = logger(QLatin1String("Log4Qt")); Logger *p_qt_logger = logger(QLatin1String("Qt")); Logger *p_root_logger = rootLogger(); Logger *p_logger; Q_FOREACH(p_logger, mLoggers) { if ((p_logger == p_logging_logger) || (p_logger == p_qt_logger) || (p_logger == p_root_logger)) continue; resetLogger(p_logger, Level::NULL_INT); } resetLogger(p_qt_logger, Level::NULL_INT); resetLogger(p_logging_logger, Level::NULL_INT); resetLogger(p_root_logger, Level::DEBUG_INT); } void Hierarchy::shutdown() { static_logger()->debug("Shutting down Hierarchy"); resetConfiguration(); } #ifndef QT_NO_DEBUG_STREAM QDebug Hierarchy::debug(QDebug &rDebug) const { rDebug.nospace() << "Hierarchy(" << "loggers:" << loggers().count() << " " << "threshold:" << threshold().toString() << " " << "root-level:" << rootLogger()->level().toString() << " " << "root-appenders:" << rootLogger()->appenders().count() << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM Logger *Hierarchy::createLogger(const QString &rName) { // Q_ASSERT_X(, "Hierarchy::createLogger", "Lock must be held by caller") const QString name_separator = QLatin1String("::"); Logger *p_logger = mLoggers.value(rName, 0); if (p_logger != 0) return p_logger; if (rName.isEmpty()) { p_logger = new Logger(this, Level::DEBUG_INT, QLatin1String("root"), 0); mLoggers.insert(QString(), p_logger); return p_logger; } QString parent_name; int index = rName.lastIndexOf(name_separator); if (index >=0) parent_name = rName.left(index); p_logger = new Logger(this, Level::NULL_INT, rName, createLogger(parent_name)); mLoggers.insert(rName, p_logger); return p_logger; } void Hierarchy::resetLogger(Logger *pLogger, Level level) const { // Q_ASSERT_X(, "Hierarchy::resetLogger", "Lock must be held by caller") pLogger->removeAllAppenders(); pLogger->setAdditivity(true); pLogger->setLevel(level); } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/loggerrepository.h0000664000175000017500000001041615167726064021436 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: loggerrepository.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_LOGGERREPOSITORY_H #define LOG4QT_LOGGERREPOSITORY_H /****************************************************************************** * Dependencies ******************************************************************************/ #include #include "log4qt/level.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { class Logger; /*! * \brief The class LoggerRepository is abstract base class for a logger * repository. */ class LIBUKUILOG4QT_EXPORT LoggerRepository { public: // LoggerRepository(); // Use compiler default // LoggerRepository(const LoggerRepository &rOther); // Use compiler default // virtual ~LoggerRepository(); // Use compiler default // LoggerRepository &operator=(const LoggerRepository &rOther); // Use compiler default public: virtual bool exists(const QString &rName) const = 0; virtual Logger *logger(const QString &rName) = 0; // JAVA: virtual Logger *logger(const String &rName, LoggerFactory *pFactory); virtual QList loggers() const = 0; virtual Logger *rootLogger() const = 0; virtual Level threshold() const = 0; virtual void setThreshold(Level level) = 0; virtual void setThreshold(const QString &rThreshold) = 0; virtual bool isDisabled(Level level) = 0; virtual void resetConfiguration() = 0; virtual void shutdown() = 0; // JAVA: virtual void addHierarchyEventListener(HierarchyEventListener *pEventListener); // JAVA: virtual void emitNoAppenderWarning(Logger *plogger) const; // JAVA: virtual void fireAddAppenderEvent(Logger *plogger, Appender *pAppender) const; protected: #ifndef QT_NO_DEBUG_STREAM /*! *\relates LoggerRepository * * Writes all object member variables to the given debug stream \a rDebug * and returns the stream. * * The member function is used by * QDebug operator<<(QDebug debug, const LoggerRepository &rLoggerRepository) * to generate class specific output. * * \sa QDebug operator<<(QDebug debug, const LoggerRepository &rLoggerRepository) */ virtual QDebug debug(QDebug &rDebug) const = 0; friend QDebug operator<<(QDebug debug, const LoggerRepository &rLoggerRepository); #endif }; /****************************************************************************** * Operators, Helper ******************************************************************************/ #ifndef QT_NO_DEBUG_STREAM /*! * \relates LoggerRepository * Writes all object member variables to the given debug stream \a debug * and returns the stream. * * To handle subclassing the function uses the virtual member function * debug(). This allows each class to generate its own output. * * \sa QDebug, debug() */ QDebug operator<<(QDebug debug, const LoggerRepository &rLoggerRepository); #endif /************************************************************************** * Inline **************************************************************************/ } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::LoggerRepository, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_LOGGERREPOSITORY_H ukui-interface/src/log4qt/log4qt/consoleappender.cpp0000664000175000017500000001203515167726064021532 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: consoleappender.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/consoleappender.h" #include #include #include "log4qt/helpers/optionconverter.h" #include "log4qt/layout.h" #include "log4qt/loggingevent.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: ConsoleAppender **************************************************************************/ ConsoleAppender::ConsoleAppender(QObject *pParent) : WriterAppender(pParent), mTarget(STDOUT_TARGET), mpTextStream(0) { } ConsoleAppender::ConsoleAppender(Layout *pLayout, QObject *pParent) : WriterAppender(pLayout, pParent), mTarget(STDOUT_TARGET), mpTextStream(0) { } ConsoleAppender::ConsoleAppender(Layout *pLayout, const QString &rTarget, QObject *pParent) : WriterAppender(pLayout, pParent), mTarget(STDOUT_TARGET), mpTextStream(0) { setTarget(rTarget); } ConsoleAppender::ConsoleAppender(Layout *pLayout, Target target, QObject *pParent) : WriterAppender(pLayout, pParent), mTarget(target), mpTextStream(0) { } ConsoleAppender::~ConsoleAppender() { close(); } QString ConsoleAppender::target() const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe if (mTarget == STDOUT_TARGET) return QLatin1String("STDOUT_TARGET"); else return QLatin1String("STDERR_TARGET"); } void ConsoleAppender::setTarget(const QString &rTarget) { bool ok; Target target = (Target)OptionConverter::toTarget(rTarget, &ok); if (ok) setTarget(target); } void ConsoleAppender::activateOptions() { QMutexLocker locker(&mObjectGuard); closeStream(); if (mTarget == STDOUT_TARGET) mpTextStream = new QTextStream(stdout); else mpTextStream = new QTextStream(stderr); setWriter(mpTextStream); WriterAppender::activateOptions(); } void ConsoleAppender::close() { QMutexLocker locker(&mObjectGuard); if (isClosed()) return; WriterAppender::close(); closeStream(); } void ConsoleAppender::closeStream() { // Q_ASSERT_X(, "ConsoleAppender::closeStream()", "Lock must be held by caller") setWriter(0); delete mpTextStream; mpTextStream = 0; } #ifndef QT_NO_DEBUG_STREAM QDebug ConsoleAppender::debug(QDebug &rDebug) const { QString layout_name; if (layout()) layout_name = layout()->name(); QString target; if (mTarget == STDOUT_TARGET) target = QLatin1String("STDOUT"); else target = QLatin1String("STDERR"); rDebug.nospace() << "ConsoleAppender(" << "name:" << name() << " " << "filter:" << firstFilter() << " " << "isactive:" << isActive() << " " << "isclosed:" << isClosed() << " " << "layout:" << layout_name << " " << "target:" << target << " " << "referencecount:" << referenceCount() << " " << "threshold:" << threshold().toString() << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM /****************************************************************************** * Implementation: Operators, Helper ******************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/log4qt.cpp0000664000175000017500000000324315167726064017564 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: logging.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *****************************************************************************/ /****************************************************************************** *Dependencies ******************************************************************************/ #include "log4qt/log4qt.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** *Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/appenderskeleton.h0000664000175000017500000001647115167726076021374 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: appenderskeleton.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_APPENDERSKELETON_H #define LOG4QT_APPENDERSKELETON_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/appender.h" #include #include "log4qt/helpers/logobjectptr.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { class Filter; class Layout; class Logger; class LoggingEvent; /*! * \brief The class AppenderSkeleton implements general Appender functionality. * * \note All the functions declared in this class are thread-safe. * * \note The ownership and lifetime of objects of this class are managed. See * \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT AppenderSkeleton : public Appender { Q_OBJECT /*! * The property holds if the Appender has been activated. * * \sa isActive() */ Q_PROPERTY(bool isActive READ isActive) /*! * The property holds if the Appender has been closed. * * \sa isClosed() */ Q_PROPERTY(bool isClosed READ isClosed) /*! * The property holds the threshold level used by the Appender. * * \sa threshold(), setThreshold() */ Q_PROPERTY(Level threshold READ threshold WRITE setThreshold) public: AppenderSkeleton(QObject *pParent = 0); protected: AppenderSkeleton(const bool isActive, QObject *pParent = 0); public: // virtual ~AppenderSkeleton(); Use compiler default private: AppenderSkeleton(const AppenderSkeleton &rOther); // Not implemented AppenderSkeleton &operator=(const AppenderSkeleton &rOther); // Not implemented public: // JAVA: ErrorHandler* errorHandler(); virtual Filter *filter() const; virtual Layout *layout() const; bool isActive() const; bool isClosed() const; virtual QString name() const; Level threshold() const; // JAVA: void setErrorHandler(ErrorHandler *pErrorHandler); virtual void setLayout(Layout *pLayout); virtual void setName(const QString &rName); void setThreshold(Level level); virtual void activateOptions(); virtual void addFilter(Filter *pFilter); virtual void clearFilters(); virtual void close(); /*! * Performs checks and delegates the actuall appending to the subclass * specific append() function. * * \sa append(), checkEntryConditions(), isAsSevereAsThreshold(), Filter */ virtual void doAppend(const LoggingEvent &rEvent); // JAVA: void finalize(); Filter* firstFilter() const; bool isAsSevereAsThreshold(Level level) const; protected: virtual void append(const LoggingEvent &rEvent) = 0; virtual void asyncAppend(const LoggingEvent &rEvent) = 0; /*! * Tests if all entry conditions for using append() in this class are * met. * * If a conditions is not met, an error is logged and the function * returns false. * * The checked conditions are: * - That the appender has been activated (APPENDER_NOT_ACTIVATED_ERROR) * - That the appender was not closed (APPENDER_CLOSED_ERROR) * - That the appender has a layout set, if it requires one * (logging_error(APPENDER_USE_MISSING_LAYOUT_ERROR) * * The function is called as part of the checkEntryConditions() chain * started by doAppend(). The doAppend() function calls the subclass * specific checkEntryConditions() function. The function checks the * class specific conditions and calls checkEntryConditions() of * it's parent class. The last function called is * AppenderSkeleton::checkEntryConditions(). * * \sa doAppend() */ virtual bool checkEntryConditions() const; protected: #if QT_VERSION < 0x050E00 mutable QMutex mObjectGuard; #else mutable QRecursiveMutex mObjectGuard; #endif private: bool mAppendRecursionGuard; volatile bool mIsActive; volatile bool mIsClosed; LogObjectPtr mpLayout; Level mThreshold; LogObjectPtr mpHeadFilter; LogObjectPtr mpTailFilter; // need AsyncDispatcher to call asyncAppend method friend class AsyncDispatcher; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline Filter *AppenderSkeleton::filter() const { QMutexLocker locker(&mObjectGuard); return mpHeadFilter; } inline Layout *AppenderSkeleton::layout() const { QMutexLocker locker(&mObjectGuard); return mpLayout; } inline QString AppenderSkeleton::name() const { QMutexLocker locker(&mObjectGuard); return objectName(); } inline Level AppenderSkeleton::threshold() const { // QMutexLocker locker(&mObjectGuard); // Level is threadsafe return mThreshold; } inline void AppenderSkeleton::setLayout(Layout *pLayout) { QMutexLocker locker(&mObjectGuard); mpLayout = pLayout; } inline void AppenderSkeleton::setName(const QString &rName) { QMutexLocker locker(&mObjectGuard); setObjectName(rName); } inline void AppenderSkeleton::setThreshold(Level level) { // QMutexLocker locker(&mObjectGuard); // Level is threadsafe mThreshold = level; } inline bool AppenderSkeleton::isActive() const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe return mIsActive; } inline bool AppenderSkeleton::isClosed() const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe return mIsClosed; } inline Filter *AppenderSkeleton::firstFilter() const { QMutexLocker locker(&mObjectGuard); return filter(); } inline bool AppenderSkeleton::isAsSevereAsThreshold(Level level) const { // QMutexLocker locker(&mObjectGuard); // Level is threadsafe return (mThreshold <= level); } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::AppenderSkeleton, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_APPENDERSKELETON_H ukui-interface/src/log4qt/log4qt/layout.h0000664000175000017500000001063515167726076017342 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: layout.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_LAYOUT_H #define LOG4QT_LAYOUT_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/helpers/logobject.h" #include "log4qt/helpers/logobjectptr.h" #include "log4qt/log4qt.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { class LoggingEvent; /*! * \brief The class Layout is the base class for all layouts. * * \note The ownership and lifetime of objects of this class are managed. See * \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT Layout : public LogObject { Q_OBJECT /*! * The property holds the content type of the layout. * * \sa contentType() */ Q_PROPERTY(QString footercontentType READ contentType) /*! * The property holds the footer used by the layout. * * \sa footer(), setFooter() */ Q_PROPERTY(QString footer READ footer WRITE setFooter) /*! * The property holds the header used by the layout. * * \sa header(), setHeader() */ Q_PROPERTY(QString header READ header WRITE setHeader) public: Layout(QObject *pParent = 0); virtual ~Layout(); private: Layout(const Layout &rOther); // Not implemented Layout &operator=(const Layout &rOther); // Not implemented public: virtual QString contentType() const; QString footer() const; QString header() const; // JAVA: virtual bool ignoresThrowable() const; QString name() const; void setFooter(const QString &rFooter); void setHeader(const QString &rHeader); void setName(const QString &rName); // JAVA: void setIgnoresThrowable(bool) const; virtual void activateOptions(); virtual QString format(const LoggingEvent &rEvent) = 0; /*! * Returns the end of line seperator for the operating system. * * Windows: \\r\\n * Mac: \\r * UNIX: \\n */ static QString endOfLine(); // Member variables private: QString mFooter; QString mHeader; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline Layout::Layout(QObject *pParent) : LogObject(pParent) {} inline Layout::~Layout() {} inline QString Layout::footer() const { return mFooter; } inline QString Layout::header() const { return mHeader; } inline QString Layout::name() const { return objectName(); } inline void Layout::setFooter(const QString &rFooter) { mFooter = rFooter; } inline void Layout::setHeader(const QString &rHeader) { mHeader = rHeader; } inline void Layout::setName(const QString &rName) { setObjectName(rName); } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::Layout, Q_COMPLEX_TYPE); // Use default #if QT_VERSION < 0x060000 Q_DECLARE_TYPEINFO(Log4Qt::LogObjectPtr, Q_MOVABLE_TYPE); #else Q_DECLARE_TYPEINFO(Log4Qt::LogObjectPtr, Q_COMPLEX_TYPE); #endif // Qt6 compatibility: opaque pointer declared in appender.h #endif // LOG4QT_LAYOUT_H ukui-interface/src/log4qt/log4qt/log4qt.h0000664000175000017500000006276415167726064017246 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: logging.h * created: September 2007 * author: Martin Heinrich * * * changes: Sep 2008, Martin Heinrich: * - Added a compile time version check for the Qt version * Jan 2009, Martin Heinrich: * - Updated documentation and version information for version 0.2 * Feb 2009, Martin Heinrich: * - Updated version information for version 0.3 * * * Copyright 2007 - 2009 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_H #define LOG4QT_H /*! * \mainpage * * %Log4Qt is a C++ port of the Apache Software Foundation Log4j package * using the Trolltech Qt Framework. * * The documentation describes classes and methods that have been added or * changed compared to Log4j. * * The following sections are describing the implementation in more detail: * - \ref Changes "Differences to Log4j" * - \ref Ownership "Object ownership" * - \ref LogLog "Logging within the package" * - \ref Init "Initialization procedure" * - \ref Env "Environment Variables" * - \ref Undocumented "Undocumented functions" * - \ref Assumptions "Assumptions" * * \author Martin Heinrich * \version 0.3 (January 2009) * */ /*! * \page Changes Differences to Log4j * * The following fundamental differences exist between %Log4Qt and Log4j: * * - As a JAVA package Log4j does not have to manage object ownership and * lifetime in the same way then it is required in C++. For details on * how object ownership is handled see \ref Ownership "Object ownership". * - The package uses itself for its internal logging similar to Log4j 1.3. * For details see \ref LogLog "Logging within the package". * - The configuration using system properties was replaced with a combination * of environment variables and application settings. For details see * \ref Env "Environment Variables". * - Custom levels are not supported. * - Multiple Logger Repositories are not supported * * The following classes have been changed: * * - \ref Log4Qt::AppenderSkeleton "AppenderSkeleton" * - The procedure of checking, if logging is possible, originally used by * \ref Log4Qt::WriterAppender "WriterAppender" was generalised and is used * in \ref Log4Qt::AppenderSkeleton "AppenderSkeleton" and derived classes * (\ref Log4Qt::AppenderSkeleton::checkEntryConditions() "checkEntryConditions()"). * - The \ref Log4Qt::AppenderSkeleton::doAppend() "doAppend()" member function will * check the entry conditions by calling the sub-class specific * \ref Log4Qt::AppenderSkeleton::checkEntryConditions() "checkEntryConditions()". * If successful the sub-class specific * \ref Log4Qt::AppenderSkeleton::append() "append()" function is called. * * - Configurator * - Configure functions return a boolean indicating, if the configuration * was successful. * - Configure errors are accessible over * \ref Log4Qt::ConfiguratorHelper::configureError() * "ConfiguratorHelper::configureError()". * - Watching for configuration file changes is a function performed * centrally by the \ref Log4Qt::ConfiguratorHelper "ConfiguratorHelper". * The class provides signals to notify on configuration change and errors. * - The class \ref Log4Qt::PropertyConfigurator "PropertyConfigurator" was * extended to be able to read configuration data from a QSettings object. * * - \ref Log4Qt::Level "Level" * - A new value \ref Log4Qt::Level::NULL_INT "Level::NULL_INT" was * introduced to indicate there is no level set. * * - \ref Log4Qt::Logger "Logger" * - The method \ref Log4Qt::Logger::isEnabledFor() "isEnabledFor()" * does also take the repository threshold into account. * - Several overloaded convenience member function are available to log * messages with arguments of different types. * - Two macros, \ref Log4Qt::LOG4QT_DECLARE_STATIC_LOGGER "LOG4QT_DECLARE_STATIC_LOGGER" * and \ref Log4Qt::LOG4QT_DECLARE_QCLASS_LOGGER "LOG4QT_DECLARE_QCLASS_LOGGER", * allows retrieving and caching of a pointer to a logger object. * * - \ref Log4Qt::LogManager "LogManager" * - A QtMessage handler can be installed via * \ref Log4Qt::LogManager::setHandleQtMessages() "setHandleQtMessages()", * to redirect all messages created by calls to qDebug(), qWarning(), * qCritical() and qFatal() to a logger. The logger is named Qt and can be * accessed using \ref Log4Qt::LogManager::qtLogger() "qtLogger()". * - The initialisation procedure is available over a public method * (\ref Log4Qt::LogManager::startup() "startup()"). * - The LogManager provides access to the logger used internally by the * package (\ref Log4Qt::LogManager::logLogger() "logLogger()") and to * its default initialisation procedure * (\ref Log4Qt::LogManager::configureLogLogger() "configureLogLogger()"). * * - \ref Log4Qt::WriterAppender "WriterAppender" * - The class will call \ref Log4Qt::WriterAppender::handleIoErrors() * "handleIoErrors()" after all I/O operations. Sub-classes should * re-implement the function to handle errors. * * The following classes have been added: * * - An additional appender class, \ref Log4Qt::DebugAppender "DebugAppender", * was added. The class appends logging events to the platform specific debug * output. * - Various helper class have been introduced: * - \ref Log4Qt::ClassLogger "ClassLogger": The class ClassLogger provides * logging for a QObject derived class. * - \ref Log4Qt::ConfiguratorHelper "ConfiguratorHelper": The class * ConfiguratorHelper provides a configuration file watch and last error * for configurator classes. * - \ref Log4Qt::DateTime "DateTime": The class DateTime provides extended * functionality for QDateTime. * - \ref Log4Qt::LogError "LogError": The class LogError represents an error. * - \ref Log4Qt::Factory "Factory": The class Factory provides factories * for Appender, Filter and Layout objects. * - \ref Log4Qt::InitialisationHelper "InitialisationHelper": The class * InitialisationHelper performs static initialisation tasks. * - \ref Log4Qt::LogObject "LogObject": The class LogObject is the common * base class for many classes in the package. * - \ref Log4Qt::LogObjectPtr "LogObjectPtr": The class LogObjectPtr * implements automatic reference counting for LogObject objects. * - \ref Log4Qt::PatternFormatter "PatternFormatter": The class * PatternFormatter formats a logging event based on a pattern string. * - \ref Log4Qt::Properties "Properties": The class Properties implements a * JAVA property hash. */ /*! * \page Ownership Object ownership * * In difference to the JAVA Log4j package %Log4Qt must manage ownership and * lifetime of the objects used. This is non trivial as objects are created * and used in different ways. * * In general an object can be created explicitly for example an application * may create Loggers, Appenders and Layouts during creation of a QApplication * object. But they can also be automatically created by the package on * startup using a \ref Log4Qt::PropertyConfigurator "PropertyConfigurator" * configuration file. Objects may also be created the one way and then used * the other. Object may be used by multiple other objects. A Layout for example * may be used by multiple Appenders. Objects are also created from multiple * threads. The creation may happen during static initialisation and the * deletion during static de-initialization. * * The parent child model used by QObject cannot be used to handle this. It * cannot automatically delete an object that is used by multiple others as * for example an Appender used by multiple Loggers. In addition to this * QObjects and their children must reside in the same thread. This would * either mean to impose restriction on how objects can be created or to move * objects to a specific thread. * * To allow an automatic deletion of not required objects the package * implements reference counting for Appenders, Layouts and Filters. The * reference counting is implemented in \ref Log4Qt::LogObject "LogObject", * which is used as a common base class. The reference count can be explicitly * changed using the methods \ref Log4Qt::LogObject::retain() "retain()" and * \ref Log4Qt::LogObject::release() "release()". Alternatively an auto pointer * is available \ref Log4Qt::LogObjectPtr "LogObjectPtr", which is used * throughout the package. * * The reference counting mechanism will test, if an object has a QObject * parent object set. If a parent is set, the object will not be deleted, if * the reference count reaches 0. This allows to mix the reference counted * paradigm with the QObject parent child one. * * The following example configures a logger and uses reference counting to * manage the ownership of objects. * * \code * // Create layout * TTCCLayout *p_layout = new TTCCLayout(); * * // Create appender * ConsoleAppender *p_appender = new ConsoleAppender(p_layout, ConsoleAppender::STDOUT_TARGET); * p_appender->activateOptions(); * * // Get logger * Logger *p_logger = Logger::logger("MyClass"); * p_logger->addAppender(p_appender); * * // ... * * // Remove appender from Logger * p_logger->removeAllAppenders(); // p_appender and p_layout are deleted here * \endcode * * The following example configures a logger and uses QObject ownership of * objects. * * \code * QObject *p_parent = new MyObject; * * // Create objects * ConsoleAppender *p_appender = new ConsoleAppender(p_parent); * TTCCLayout *p_layout = new TTCCLayout(p_appender); * * // Configure appender * p_appender->setTarget(ConsoleAppender::STDOUT_TARGET); * p_appender->setLayout(p_layout); * p_appender->activateOptions(); * * // Get logger * Logger *p_logger = Logger::logger("MyClass"); * p_logger->addAppender(p_appender); * * // ... * * // Remove appender from Logger * p_logger->removeAllAppenders(); * * delete p_parent; // p_appender and p_layout are deleted here * \endcode * * The following example shows how to use objects created on the stack. * * \code * { * // Create layout * TTCCLayout layout; * layout.retain(); * * // Create appender * ConsoleAppender appender(&layout, ConsoleAppender::STDOUT_TARGET); * appender.retain(); * appender.activateOptions(); * * // Get logger * Logger *p_logger = Logger::logger("MyClass"); * p_logger->addAppender(&appender); * * // ... * * // Remove appender from Logger * p_logger->removeAllAppenders(); // Without retain() program crashes here * * } // p_appender and p_layout are deleted here * \endcode */ /*! * \page LogLog Logging within the package * * The package uses itself for logging similar to Log4j 1.3. This brings much * more flexibility over logging to stdout, stderr like in Log4j 1.2 using * logLog. It also enables the program to capture and handle errors raised by * the package. * * Using this approach introduces the issue of recursion. The following example * explains a situation where this happens. Let's say all logger are configured * to be additive and only the root logger has an appender set. The appender * is a \ref Log4Qt::FileAppender "FileAppender". During the logging of an * event an I/O error occurs. The \ref Log4Qt::FileAppender "FileAppender" logs * an event by itself using the logger %Log4Qt::FileAppender. The event is * passed to the root logger, which calls then the \ref Log4Qt::FileAppender * "FileAppender". This causes another I/O error, which is logged by * the \ref Log4Qt::FileAppender "FileAppender". * * To avoid an endless loop the appender will drop the event on a recursive * invocation. This check is done by \ref Log4Qt::AppenderSkeleton * "AppenderSkeleton" in \ref Log4Qt::AppenderSkeleton::doAppend() * "doAppend()". * * The problem only occurs, if a logger, appender, layout or filter log an * event while an event is appended. Neither the logger class nor any of the * layout or filter classes log events during appending of an event. Most of * the appender classes may log errors during appending. Only the * \ref Log4Qt::ListAppender "ListAppender" and * \ref Log4Qt::ListAppender "ConsoleAppender" are not logging events. * * The default configuration uses two \ref Log4Qt::ListAppender * "ConsoleAppender", one for stderr and one for stdout. No event will be * dropped, because no recursive invocations can occur. */ /*! * \page Init Initialization procedure * * The package is initialised in two stages. The first stage takes place during * static initialization. The second stage takes place when the * \ref Log4Qt::LogManager "LogManager" singleton is created. * * During static initialisation the \ref Log4Qt::InitialisationHelper * "InitialisationHelper" singleton is created . On construction it captures * the program startup time, reads the required values from the system * environment and registers the package types with the Qt type system. * * The \ref Log4Qt::LogManager "LogManager" singleton is created on first use. * The creation is usually triggered by the request for a \ref Log4Qt::Logger * "Logger" object. The call to \ref Log4Qt::Logger::logger() * "Logger::logger()" is passed through to \ref Log4Qt::LogManager::logger() * "LogManager::logger()". On creation the \ref Log4Qt::LogManager "LogManager" * creates a \ref Log4Qt::Hierarchy "Hierarchy" object as logger repository. * * After the singleton is created the logging of the package is configured to * its default by a call to \ref Log4Qt::LogManager::configureLogLogger() * "LogManager::configureLogLogger()". The logger * \ref Log4Qt::LogManager::logLogger() "logLogger()" is configured to be not * additive. Messages with the level \ref Log4Qt::Level::ERROR_INT * "Level::ERROR_INT" and \ref Log4Qt::Level::FATAL_INT "Level::FATAL_INT" are * written to \c stderr using a ConsoleAppender. The remaining messages are * written to \c stdout using a second ConsoleAppender. The level is read from * the system environment or application settings using * \ref Log4Qt::InitialisationHelper::setting() * "InitialisationHelper::setting()" with the key \c Debug. If a level value * is found, but it is not a valid Level string, * \ref Log4Qt::Level::DEBUG_INT "Level::DEBUG_INT" is used. If no level string * is found \ref Log4Qt::Level::ERROR_INT "Level::ERROR_INT" is used. * * Once the logging is configured the package is initialised by a call to * \ref Log4Qt::LogManager::startup() "LogManager::startup()". The function * will test for the setting \c DefaultInitOverride in the system environment * and application settings using \ref Log4Qt::InitialisationHelper::setting() * "InitialisationHelper::setting()". If the value is present and set to * anything else then \c false, the initialisation is aborted.
* The system environment and application settings are tested for the setting * \c Configuration. If it is found and it is a valid path to a file, the * package is configured with the file using * \ref Log4Qt::PropertyConfigurator::doConfigure(const QString &, LoggerRepository *) * "PropertyConfigurator::doConfigure()". If the setting \c Configuration is * not available and a QCoreApplication object is present, the application * settings are tested for a group \c Log4Qt/Properties. If the group exists, * the package is configured with the setting using the * \ref Log4Qt::PropertyConfigurator::doConfigure(const QSettings &r, LoggerRepository *) * "PropertyConfiguratordoConfigure()". If neither a configuration file nor * configuration settings could be found, the current working directory is * searched for the file \c "log4qt.properties". If it is found, the package * is configured with the file using * \ref Log4Qt::PropertyConfigurator::doConfigure(const QString &, LoggerRepository *) * "PropertyConfigurator::doConfigure()". * * The following example shows how to use application settings to initialise the * package. * * \code * # file: myapplication.h * * #include qapplication.h * * class MyApplication : public QApplication * { * Q_OBJECT * * public: * MyApplication(); * ~MyApplication(); * void setupLog4Qt(); * } * \endcode * \code * # file: myapplication.cpp * * #include myapplication.h * * MyApplication::MyApplication( * { * // Set Application data to allow Log4Qt initialisation to read the * // correct values * setApplicationName("MyApplication"); * setOrganisationName("MyOrganisation"); * setOrganizationDomain("www.myorganisation.com"); * * // Log first message, which initialises Log4Qt * Log4Qt::Logger::logger("MyApplication")->info("Hello World"); * } * * MyApplication::~MyApplication() * { * } * * void MyApplication::setupLog4Qt() * { * QSettings s; * * // Set logging level for Log4Qt to TRACE * s.beginGroup("Log4Qt"); * s.setValue("Debug", "TRACE"); * * // Configure logging to log to the file C:/myapp.log using the level TRACE * s.beginGroup("Properties"); * s.setValue("log4j.appender.A1", "org.apache.log4j.FileAppender"); * s.setValue("log4j.appender.A1.file", "C:/myapp.log"); * s.setValue("log4j.appender.A1.layout", "org.apache.log4j.TTCCLayout"); * s.setValue("log4j.appender.A1.layout.DateFormat", "ISO8601"); * s.setValue("log4j.rootLogger", "TRACE, A1"); * * // Settings will become active on next application startup * } * \endcode */ /*! * \page Env Environment Variables * * The package uses environment variables to control the initialization * procedure. The environment variables replace the system property entries * used by Log4j. * * For compability reasons the Log4j entry is recognised. Alternatively a * environment variable style Log4Qt form can be used. The following entries * are used: * * - LOG4QT_DEBUG
* The variable controls the \ref Log4Qt::Level "Level" value for the * logger \ref Log4Qt::LogManager::logLogger() "LogManager::logLogger()". * If the value is a valid \ref Log4Qt::Level "Level" string, the level for * the is set to the level. If the value is not a valid * \ref Log4Qt::Level "Level" string, \ref Log4Qt::Level::DEBUG_INT * "DEBUG_INT" is used. Otherwise \ref Log4Qt::Level::ERROR_INT "ERROR_INT" * is used. * - \ref Log4Qt::LogManager::configureLogLogger() * "LogManager::configureLogLogger()" * * - LOG4QT_DEFAULTINITOVERRIDE
* The variable controls the \ref Init "initialization procedure" performed * by the \ref Log4Qt::LogManager "LogManager" on startup. If it is set to * any other value then \c false the \ref Init "initialization procedure" * is skipped. * - \ref Log4Qt::LogManager::startup() "LogManager::startup()" * * - LOG4QT_CONFIGURATION
* The variable specifies the configuration file used for initialising the * package. * - \ref Log4Qt::LogManager::startup() "LogManager::startup()" * * - LOG4QT_CONFIGURATORCLASS
* The variable specifies the configurator class used for initialising the * package. * * Environment variables are read during static initialisation on creation of * the \ref Log4Qt::InitialisationHelper "InitialisationHelper". They can be * accessed by calling \ref Log4Qt::InitialisationHelper::environmentSettings() * "InitialisationHelper::environmentSettings()". * * All settings can also be made in the application settings under the group * \c %Log4Qt. For example the environment variable \c LOG4QT_DEBUG is * equivalent to the setting \c Log4Qt/Debug. If an environment variable is * set it takes precedence over the application setting. Settings are only * used, if an QApplication object is available, when the * \ref Log4Qt::LogManager "LogManager" is * initialised (see \ref Log4Qt::InitialisationHelper::setting() * "InitialisationHelper::setting()" for details). */ /*! * \page Undocumented Undocumented functions * * In general it was tried to avoid the usage of undocumented features of Qt. * Nice to have features like for example Q_DECLARE_PRIVATE are not used. Only * features that would have been resulted in re-coding the same functionality * are used. * * - QT_WA: The macro is used to call Windows A/W functions * - \ref Log4Qt::DebugAppender "DebugAppender" * - QBasicAtomicPointer: The class is used instead of QAtomicPointer, because * it allows the initialisation as plain old data type. * - \ref Log4Qt::LOG4QT_GLOBAL_STATIC "LOG4QT_GLOBAL_STATIC" * - \ref Log4Qt::LOG4QT_IMPLEMENT_INSTANCE "LOG4QT_IMPLEMENT_INSTANCE" * - \ref Log4Qt::LOG4QT_DECLARE_STATIC_LOGGER "LOG4QT_DECLARE_STATIC_LOGGER" * - Q_BASIC_ATOMIC_INITIALIZER: The macro is used to initialise QAtomicPointer * objects as plain old data type. * - \ref Log4Qt::LOG4QT_GLOBAL_STATIC "LOG4QT_GLOBAL_STATIC" * - \ref Log4Qt::LOG4QT_IMPLEMENT_INSTANCE "LOG4QT_IMPLEMENT_INSTANCE" * - \ref Log4Qt::LOG4QT_DECLARE_STATIC_LOGGER "LOG4QT_DECLARE_STATIC_LOGGER" */ /*! * \page Assumptions Assumptions * * The following assumptions are used throughout the package: * * - Reading / writing of bool or int is thread-safe, if declared volatile * - \ref Log4Qt::ListAppender "ListAppender" * - \ref Log4Qt::AppenderSkeleton "AppenderSkeleton" * - \ref Log4Qt::ConsoleAppender "ConsoleAppender" * - \ref Log4Qt::FileAppender "FileAppender" * - \ref Log4Qt::Hierarchy "Hierarchy" * - \ref Log4Qt::Level "Level" * - \ref Log4Qt::Logger "Logger" * - \ref Log4Qt::WriterAppender "WriterAppender" * - \ref Log4Qt::Layout::format() "Layout::format()" is implemented reentrant * in all sub-classes. * - \ref Log4Qt::AppenderSkeleton "AppenderSkeleton" * - Being able to use singleton objects during static de-initialization without * order issues is more valuable then their destruction. * - \ref Log4Qt::LogManager "LogManager" * - \ref Log4Qt::LOG4QT_GLOBAL_STATIC "LOG4QT_GLOBAL_STATIC" * - \ref Log4Qt::LOG4QT_IMPLEMENT_INSTANCE "LOG4QT_IMPLEMENT_INSTANCE" */ /****************************************************************************** * Dependencies ******************************************************************************/ #include #include "ukui-logmacros.h" #if QT_VERSION < QT_VERSION_CHECK(4, 3, 0) # error "Log4Qt requires Qt version 4.3.0 or higher" #endif /****************************************************************************** * Declarations ******************************************************************************/ /*! * \brief The namespace %Log4Qt encloses all parts of the package. */ namespace Log4Qt { /*! * This macro expands a numeric value of the form 0xMMmmPP (MM = major, * mm = minor, PP = patch) that specifies Log4Qt's version number. * This is the version against which the application is compiled. * * \sa \ref Log4Qt::LOG4QT_VERSION_STR "LOG4QT_VERSION_STR", * \ref Log4Qt::LogManager::version() "LogManager::version()" */ #define LOG4QT_VERSION 0x000200 /*! * The macro expands to a string that specifies the Log4Qt's version * number. This is the version against which the application is compiled. * * \sa \ref Log4Qt::LOG4QT_VERSION "LOG4QT_VERSION", * \ref Log4Qt::LogManager::version() "LogManager::version()" */ #define LOG4QT_VERSION_STR "0.3.0" enum ErrorCode { OK = 0, // AppenderSkeleton, FileAppender, WriterAppender APPENDER_ACTIVATE_MISSING_LAYOUT_ERROR, APPENDER_ACTIVATE_MISSING_WRITER_ERROR, APPENDER_ACTIVATE_MISSING_FILE_ERROR, APPENDER_CLOSED_ERROR, APPENDER_INVALID_PATTERN_ERROR, APPENDER_NO_OPEN_FILE_ERROR, APPENDER_NOT_ACTIVATED_ERROR, APPENDER_OPENING_FILE_ERROR, APPENDER_RENAMING_FILE_ERROR, APPENDER_REMOVE_FILE_ERROR, APPENDER_USE_INVALID_PATTERN_ERROR, APPENDER_USE_MISSING_LAYOUT_ERROR, APPENDER_USE_MISSING_WRITER_ERROR, APPENDER_WRITING_FILE_ERROR, // Level LEVEL_INVALID_LEVEL_STRING, // Layouts, PatternFormatter LAYOUT_EXPECTED_DIGIT_ERROR, LAYOUT_OPTION_IS_NOT_INTEGER_ERROR, LAYOUT_INTEGER_IS_NOT_POSITIVE_ERROR, // Logger LOGGER_INVALID_LEVEL_FOR_ROOT, // PropertyConfigurator, OptionHandler CONFIGURATOR_OPENING_FILE_ERROR, CONFIGURATOR_READING_FILE_ERROR, CONFIGURATOR_INVALID_SUBSTITUTION_ERROR, CONFIGURATOR_INVALID_OPTION_ERROR, CONFIGURATOR_MISSING_APPENDER_ERROR, CONFIGURATOR_UNKNOWN_APPENDER_CLASS_ERROR, CONFIGURATOR_MISSING_LAYOUT_ERROR, CONFIGURATOR_UNKNOWN_LAYOUT_CLASS_ERROR, CONFIGURATOR_PROPERTY_ERROR, CONFIGURATOR_UNKNOWN_TYPE_ERROR }; /****************************************************************************** * Operators, Helpers ******************************************************************************/ /****************************************************************************** * Inline ******************************************************************************/ } // namespace Log4Qt #endif // LOG4QT_H ukui-interface/src/log4qt/log4qt/appender.h0000664000175000017500000001040615167726076017617 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: appender.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ********************************************************************************/ #ifndef LOG4QT_APPENDER_H #define LOG4QT_APPENDER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/helpers/logobject.h" #include "log4qt/helpers/logobjectptr.h" #include "log4qt/logger.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { class Filter; class Layout; class LoggingEvent; /*! * \brief The class Appender is the base class for all Appenders. * * To allow the whole hirarchy to be an ascendant of QObject Appender is * not an interface. * * \note All the functions declared in this class are thread-safe. * * \note The ownership and lifetime of objects of this class are managed. * See \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT Appender : public LogObject { Q_OBJECT /*! * The property holds the Layout used by the Appender. * * \sa layout(), setLayout() */ Q_PROPERTY(Layout* layout READ layout WRITE setLayout) /*! * The property holds the name of the Appender. * * \sa name(), setName() */ Q_PROPERTY(QString name READ name WRITE setName) /*! * The property holds if the Appender requires a Layout or not. * * \sa requiresLayout(), setRequiresLayout() */ Q_PROPERTY(bool requiresLayout READ requiresLayout) public: Appender(QObject *pParent = 0); virtual ~Appender(); private: Appender(const Appender &rOther); // Not implemented Appender &operator=(const Appender &rOther); // Not implemented public: // JAVA: ErrorHandler* errorHandler(); virtual Filter *filter() const = 0; virtual QString name() const = 0; virtual Layout *layout() const = 0; virtual bool requiresLayout() const = 0; // JAVA: void setErrorHandler(ErrorHandler *pErrorHandler); virtual void setLayout(Layout *pLayout) = 0; virtual void setName(const QString &rName) = 0; virtual void addFilter(Filter *pFilter) = 0; virtual void clearFilters() = 0; virtual void close() = 0; virtual void doAppend(const LoggingEvent &rEvent) = 0; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline Appender::Appender(QObject *pParent) : LogObject(pParent) {} inline Appender::~Appender() {} } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::Appender, Q_COMPLEX_TYPE); // Use default #if QT_VERSION < 0x060000 Q_DECLARE_TYPEINFO(Log4Qt::LogObjectPtr, Q_MOVABLE_TYPE); #else Q_DECLARE_TYPEINFO(Log4Qt::LogObjectPtr, Q_COMPLEX_TYPE); #endif // Qt6 compatibility: declare opaque pointers for incomplete types #if QT_VERSION >= 0x060000 Q_DECLARE_OPAQUE_POINTER(Log4Qt::Layout*) Q_DECLARE_OPAQUE_POINTER(Log4Qt::Filter*) Q_DECLARE_OPAQUE_POINTER(Log4Qt::LoggingEvent*) #endif #endif // LOG4QT_APPENDER_H ukui-interface/src/log4qt/log4qt/basicconfigurator.h0000664000175000017500000000504715167726064021527 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: basicconfigurator.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_BASICCONFIGURATOR_H #define LOG4QT_BASICCONFIGURATOR_H /****************************************************************************** * Dependencies ******************************************************************************/ #include #include "log4qt/log4qt.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { class Appender; /*! * \brief The class BasicConfigurator provides a simple package * configuration. * * \note All the functions declared in this class are thread-safe. */ class LIBUKUILOG4QT_EXPORT BasicConfigurator { private: BasicConfigurator(); // Not implemented // BasicConfigurator(const BasicConfigurator &rOther); // Use compiler default // virtual ~BasicConfigurator(); // Use compiler default // BasicConfigurator &operator=(const BasicConfigurator &rOther); // Use compiler default public: static bool configure(); static void configure(Appender *pAppender); static void resetConfiguration(); }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ } // namspace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::BasicConfigurator, Q_MOVABLE_TYPE); // Use default #endif // LOG4QT_BASICCONFIGURATOR_H ukui-interface/src/log4qt/log4qt/propertyconfigurator.h0000664000175000017500000001523315167726064022330 0ustar fengfeng/****************************************************************************** * * package: Logging * file: propertyconfigurator.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_PROPERTYCONFIGURATOR_H #define LOG4QT_PROPERTYCONFIGURATOR_H /****************************************************************************** * Dependencies ******************************************************************************/ #include #include "log4qt/helpers/logobjectptr.h" #include "log4qt/log4qt.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ class QSettings; namespace Log4Qt { class Appender; class Layout; class ListAppender; class Logger; class Properties; class LoggerRepository; /*! * \brief The class PropertyConfigurator allows the configuration of the * package from a JAVA properties file. * * \note All the functions declared in this class are thread-safe. */ class LIBUKUILOG4QT_EXPORT PropertyConfigurator { public: PropertyConfigurator(); // virtual ~PropertyConfigurator(); // Use compiler default private: PropertyConfigurator(const PropertyConfigurator &rOther); // Not implemented PropertyConfigurator &operator=(const PropertyConfigurator &rOther); // Not implemented public: /*! * \sa ConfiguratorHelper::configureError() */ bool doConfigure(const Properties &rProperties, LoggerRepository *pLoggerRepository = 0); /*! * \sa ConfiguratorHelper::configureError() */ bool doConfigure(const QString &rConfigFileName, LoggerRepository *pLoggerRepository = 0); /*! * Reads the configuration data from the QSettings object * \a rSettings. * * \sa \ref Properties::load(const QSettings &) "Properties::load()", * ConfiguratorHelper::configureError() */ bool doConfigure(const QSettings &rSettings, LoggerRepository *pLoggerRepository = 0); // JAVA: void doConfigure(const QUrl &rUrl, LoggerRepository *pLoggerRepository); /*! * \sa ConfiguratorHelper::configureError() */ static bool configure(const Properties &rProperties); /*! * \sa ConfiguratorHelper::configureError() */ static bool configure(const QString &rConfigFilename); /*! * Reads the configuration data from the QSettings object * \a rSettings. * * \sa \ref doConfigure(const QSettings &, LoggerRepository *) "doConfigure()", * \ref Properties::load(const QSettings &) "Properties::load()", * ConfiguratorHelper::configureError() */ static bool configure(const QSettings &rSettings); // JAVA: static void configure(const QUrl &rUrl); /*! * \sa ConfiguratorHelper::configureError(), * ConfiguratorHelper::configurationFile() */ static bool configureAndWatch(const QString &rConfigFilename); private: void configureFromFile(const QString &rConfigFileName, LoggerRepository *pLoggerRepository); void configureFromProperties(const Properties &rProperties, LoggerRepository *pLoggerRepository); void configureFromSettings(const QSettings &rSettings, LoggerRepository *pLoggerRepository); void configureGlobalSettings(const Properties &rProperties, LoggerRepository *pLoggerRepository) const; void configureNonRootElements(const Properties &rProperties, LoggerRepository *pLoggerRepository); void configureRootLogger(const Properties &rProperties, LoggerRepository *pLoggerRepository); void parseAdditivityForLogger(const Properties &rProperties, Logger *pLogger, const QString &rLog4jName) const; LogObjectPtr parseAppender(const Properties &rProperties, const QString &rName); LogObjectPtr parseLayout(const Properties &rProperties, const QString &rAppenderName); void parseLogger(const Properties &rProperties, Logger *pLogger, const QString &rKey, const QString &rValue); void setProperties(const Properties &rProperties, const QString &rPrefix, const QStringList &rExclusions, QObject *pObject); void startCaptureErrors(); bool stopCaptureErrors(); private: LogObjectPtr mpConfigureErrors; QHash< QString, LogObjectPtr > mAppenderRegistry; }; /************************************************************************** * Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM /*! * \relates PropertyConfigurator * * Writes all object member variables to the given debug stream \a debug * and returns the stream. * * * %PropertyConfigurator() * * \sa QDebug */ QDebug operator<<(QDebug debug, const PropertyConfigurator &rPropertyConfigurator); #endif /************************************************************************** * Inline **************************************************************************/ inline PropertyConfigurator::PropertyConfigurator() {} } // namspace Logging // Q_DECLARE_TYPEINFO(Log4Qt::PropertyConfigurator, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_PROPERTYCONFIGURATOR_H ukui-interface/src/log4qt/log4qt/writerappender.h0000664000175000017500000001650415167726076021061 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: writerappender.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_WRITERAPPENDER_H #define LOG4QT_WRITERAPPENDER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/appenderskeleton.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ #if QT_VERSION >= 0x060000 #include #endif #if QT_VERSION < 0x060000 class QTextCodec; #endif class QTextStream; namespace Log4Qt { class AsyncDispatcher; /*! * \brief The class WriterAppender appends log events to a QTextStream. * * \note All the functions declared in this class are thread-safe. *   * \note The ownership and lifetime of objects of this class are managed. * See \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT WriterAppender : public AppenderSkeleton { Q_OBJECT /*! * The property holds the codec the appender uses. * * The default is null to use the codec the writer has set. * * \sa encoding(), setEncoding() */ #if QT_VERSION < 0x060000 Q_PROPERTY(QTextCodec *encoding READ encoding WRITE setEncoding) #else Q_PROPERTY(QStringConverter::Encoding encoding READ encoding WRITE setEncoding) #endif /*! * The property holds the writer the appender uses. * * \sa writer(), setWriter() */ Q_PROPERTY(QTextStream* writer READ writer WRITE setWriter) /*! * The property holds, if the writer flushes after all write operations. * * The default is true for flushing. * * \sa immediateFlush(), setImmediateFlush() */ Q_PROPERTY(bool immediateFlush READ immediateFlush WRITE setImmediateFlush) public: WriterAppender(QObject *pParent = 0); WriterAppender(Layout *pLayout, QObject *pParent = 0); WriterAppender(Layout *pLayout, QTextStream *pTextStream, QObject *pParent = 0); virtual ~WriterAppender(); private: WriterAppender(const WriterAppender &rOther); // Not implemented WriterAppender &operator=(const WriterAppender &rOther); // Not implemented void closeInternal(); public: virtual bool requiresLayout() const; #if QT_VERSION < 0x060000 QTextCodec *encoding() const; #else QStringConverter::Encoding encoding() const; #endif bool immediateFlush() const; QTextStream *writer() const; /*! * Sets the codec used by the writer to \a pTextCoded. * * If a codec is set with setEncoding, it will overwrite the codec set * in the text stream. A subsequent call with \a pTextCoded equals null * will resets the codec to the default QTextCodec::codecForLocale(). * * \sa encoding(), QTextSream::setCodec(), QTextCodec::codecForLocale() */ #if QT_VERSION < 0x060000 void setEncoding(QTextCodec *encoding); #else void setEncoding(QStringConverter::Encoding encoding); #endif void setImmediateFlush(bool immediateFlush); void setWriter(QTextStream *pTextStream); virtual void activateOptions(); virtual void close(); protected: virtual void append(const LoggingEvent &rEvent); virtual void asyncAppend(const LoggingEvent &rEvent); /*! * Tests if all entry conditions for using append() in this class are * met. * * If a conditions is not met, an error is logged and the function * returns false. Otherwise the result of * AppenderSkeleton::checkEntryConditions() is returned. * * The checked conditions are: * - A writer has been set (APPENDER_USE_MISSING_WRITER_ERROR) * * The function is called as part of the checkEntryConditions() chain * started by AppenderSkeleton::doAppend(). * * \sa AppenderSkeleton::doAppend(), * AppenderSkeleton::checkEntryConditions() */ virtual bool checkEntryConditions() const; void closeWriter(); #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream * \a rDebug and returns the stream. * * * %WriterAppender(name:"WA" encoding:"" immediateFlush:true * isactive:false isclosed:false layout:"TTCC" * referencecount:1 threshold:"NULL" * writer:0x0) * * \sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject ) */ virtual QDebug debug(QDebug &rDebug) const; #endif // QT_NO_DEBUG_STREAM virtual bool handleIoErrors() const; void writeFooter() const; void writeHeader() const; private: #if QT_VERSION < 0x060000 QTextCodec *mEncoding; #else QStringConverter::Encoding mEncoding; #endif QTextStream *mpWriter; volatile bool mImmediateFlush; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ #if QT_VERSION < 0x060000 inline QTextCodec *WriterAppender::encoding() const { QMutexLocker locker(&mObjectGuard); return mEncoding; } #else inline QStringConverter::Encoding WriterAppender::encoding() const { QMutexLocker locker(&mObjectGuard); return mEncoding; } #endif inline bool WriterAppender::immediateFlush() const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe return mImmediateFlush; } inline QTextStream *WriterAppender::writer() const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe return mpWriter; } inline void WriterAppender::setImmediateFlush(bool immediateFlush) { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe mImmediateFlush = immediateFlush; } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::WriterAppender, Q_COMPLEX_TYPE); // Use default // Qt6 compatibility: declare opaque pointers for incomplete types #if QT_VERSION >= 0x060000 Q_DECLARE_OPAQUE_POINTER(QTextStream*) #endif #endif // LOG4QT_WRITERAPPENDER_H ukui-interface/src/log4qt/log4qt/hierarchy.h0000664000175000017500000001124215167726064017773 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: hierarchy.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_HIERARCHY_H #define LOG4QT_HIERARCHY_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/loggerrepository.h" #include "ukui-logmacros.h" #include #include /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * \brief The class Hierarchy implements a logger repository. * * \note All the functions declared in this class are thread-safe. */ class LIBUKUILOG4QT_EXPORT Hierarchy : public LoggerRepository { public: Hierarchy(); // Hierarchy(const Hierarchy &rOther); // Use compiler default virtual ~Hierarchy(); // Hierarchy &operator=(const Hierarchy &rOther); // Use compiler default public: virtual bool exists(const QString &rName) const; virtual Logger *logger(const QString &rName); virtual QList loggers() const; // JAVA: virtual Logger *logger(const String &rName, LoggerFactory *pFactory); virtual Logger *rootLogger() const; virtual Level threshold() const; virtual void setThreshold(Level level); virtual void setThreshold(const QString &rThreshold); // JAVA: void clear(); virtual bool isDisabled(Level level); virtual void resetConfiguration(); virtual void shutdown(); // JAVA: virtual void addHierarchyEventListener(HierarchyEventListener *pEventListener); // JAVA: virtual void emitNoAppenderWarning(Logger *plogger) const; // JAVA: virtual void fireAddAppenderEvent(Logger *plogger, Appender *pAppender) const; // JAVA: void addRenderer(const QString &rClass, ObjectRenderer *pObjectRenderer); // JAVA: QHash getRendererMap() const; // JAVA: setRenderer(const QString &rClass, ObjectRenderer *pObjectRenderer); protected: #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream \a rDebug and * returns the stream. * * * %Hierarchy(loggers:6 threshold:"ALL" root-level:"DEBUG" root-appenders:0) * * \sa QDebug, operator<<(QDebug debug, const LoggerRepository &rLoggerRepository) */ virtual QDebug debug(QDebug &rdebug) const; #endif private: Logger *createLogger(const QString &rName); void resetLogger(Logger *pLogger, Level level) const; private: mutable QReadWriteLock mObjectGuard; QHash mLoggers; volatile bool mHandleQtMessages; Level mThreshold; Logger *mpRootLogger; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline Logger *Hierarchy::rootLogger() const { // QReadLocker locker(&mObjectGuard); // Constant for object lifetime return mpRootLogger; } inline Level Hierarchy::threshold() const { // QReadLocker locker(&mObjectGuard); // Level is threadsafe return mThreshold; } inline void Hierarchy::setThreshold(Level level) { // QReadLocker locker(&mObjectGuard); // Level is threadsafe mThreshold = level; } inline bool Hierarchy::isDisabled(Level level) { // QReadLocker locker(&mObjectGuard); // Level is threadsafe return level < mThreshold; } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::Hierarchy, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_HIERARCHY_H ukui-interface/src/log4qt/log4qt/propertyconfigurator.cpp0000664000175000017500000005364115167726064022670 0ustar fengfeng/****************************************************************************** * * package: Logging * file: propertyconfigurator.cpp * created: September 2007 * author: Martin Heinrich * * * changes Feb 2009, Martin Heinrich * - Fixed VS 2008 unreferenced formal parameter warning by using * Q_UNUSED in operator<<. * * * Copyright 2007 - 2009 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/propertyconfigurator.h" #include #include #include "log4qt/helpers/configuratorhelper.h" #include "log4qt/helpers/factory.h" #include "log4qt/helpers/optionconverter.h" #include "log4qt/helpers/properties.h" #include "log4qt/appender.h" #include "log4qt/layout.h" #include "log4qt/logger.h" #include "log4qt/logmanager.h" #include "log4qt/loggerrepository.h" #include "log4qt/varia/listappender.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ LOG4QT_DECLARE_STATIC_LOGGER(logger, Log4Qt::PropertyConfigurator) /************************************************************************** * Class implementation: PropertyConfigurator **************************************************************************/ bool PropertyConfigurator::doConfigure(const Properties &rProperties, LoggerRepository *pLoggerRepository) { startCaptureErrors(); configureFromProperties(rProperties, pLoggerRepository); return stopCaptureErrors(); } bool PropertyConfigurator::doConfigure(const QString &rConfigFileName, LoggerRepository *pLoggerRepository) { startCaptureErrors(); configureFromFile(rConfigFileName, pLoggerRepository); return stopCaptureErrors(); } bool PropertyConfigurator::doConfigure(const QSettings &rSettings, LoggerRepository *pLoggerRepository) { startCaptureErrors(); configureFromSettings(rSettings, pLoggerRepository); return stopCaptureErrors(); } bool PropertyConfigurator::configure(const Properties &rProperties) { PropertyConfigurator configurator; return configurator.doConfigure(rProperties); } bool PropertyConfigurator::configure(const QString &rConfigFilename) { PropertyConfigurator configurator; return configurator.doConfigure(rConfigFilename); } bool PropertyConfigurator::configure(const QSettings &rSettings) { PropertyConfigurator configurator; return configurator.doConfigure(rSettings); } bool PropertyConfigurator::configureAndWatch(const QString &rConfigFileName) { // Stop an existing watch to avoid a possible concurrent configuration ConfiguratorHelper::setConfigurationFile(); if (rConfigFileName.isEmpty()) return true; PropertyConfigurator configurator; bool result = configurator.doConfigure(rConfigFileName); ConfiguratorHelper::setConfigurationFile(rConfigFileName, configure); return result; } void PropertyConfigurator::configureFromFile(const QString &rConfigFileName, LoggerRepository *pLoggerRepository) { QFile file(rConfigFileName); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { LogError e = LOG4QT_ERROR(QT_TR_NOOP("Unable to open property file '%1'"), CONFIGURATOR_OPENING_FILE_ERROR, "Log4Qt::PropertyConfigurator"); e << rConfigFileName; e.addCausingError(LogError(file.errorString(), file.error())); logger()->error(e); return; } Properties properties; properties.load(&file); if (file.error()) { LogError e = LOG4QT_ERROR(QT_TR_NOOP("Unable to read property file '%1'"), CONFIGURATOR_READING_FILE_ERROR, "Log4Qt::PropertyConfigurator"); e << rConfigFileName; e.addCausingError(LogError(file.errorString(), file.error())); logger()->error(e); return; } configureFromProperties(properties, pLoggerRepository); } void PropertyConfigurator::configureFromProperties(const Properties &rProperties, LoggerRepository *pLoggerRepository) { if (!pLoggerRepository) pLoggerRepository = LogManager::loggerRepository(); configureGlobalSettings(rProperties, pLoggerRepository); configureRootLogger(rProperties, pLoggerRepository); configureNonRootElements(rProperties, pLoggerRepository); mAppenderRegistry.clear(); } void PropertyConfigurator::configureFromSettings(const QSettings &rSettings, LoggerRepository *pLoggerRepository) { Properties properties; properties.load(rSettings); configureFromProperties(properties, pLoggerRepository); } void PropertyConfigurator::configureGlobalSettings(const Properties &rProperties, LoggerRepository *pLoggerRepository) const { Q_ASSERT_X(pLoggerRepository, "PropertyConfigurator::configureGlobalSettings()", "pLoggerRepository must not be null."); const QLatin1String key_reset("log4j.reset"); const QLatin1String key_debug("log4j.Debug"); const QLatin1String key_config_debug("log4j.configDebug"); const QLatin1String key_threshold("log4j.threshold"); const QLatin1String key_handle_qt_messages("log4j.handleQtMessages"); // Test each global setting and set it // - Reset: log4j.reset // - Debug: log4j.Debug, log4j.configDebug // - Threshold: log4j.threshold // - Handle Qt Messages: log4j.handleQtMessages // Reset QString value = rProperties.property(key_reset); if (!value.isEmpty() && OptionConverter::toBoolean(value, false)) { // Use LogManager and not pLoggerRepository to reset internal // logging. LogManager::resetConfiguration(); logger()->debug("Reset configuration"); } // Debug value = rProperties.property(key_debug); if (value.isNull()) { value = rProperties.property(key_config_debug); if (!value.isNull()) logger()->warn("[%1] is deprecated. Use [%2] instead.", key_config_debug, key_debug); } if (!value.isNull()) { // Don't use OptionConverter::toLevel(). Invalid level string is a valid setting bool ok; Level level = Level::fromString(value, &ok); if (!ok) level = Level::DEBUG_INT; LogManager::logLogger()->setLevel(level); logger()->debug("Set level for Log4Qt logging to %1", LogManager::logLogger()->level().toString()); } // Threshold value = rProperties.property(key_threshold); if (!value.isNull()) { pLoggerRepository->setThreshold(OptionConverter::toLevel(value, Level::ALL_INT)); logger()->debug("Set threshold for LoggerRepository to %1", pLoggerRepository->threshold().toString()); } // Handle Qt messages value = rProperties.property(key_handle_qt_messages); if (!value.isNull()) { LogManager::setHandleQtMessages(OptionConverter::toBoolean(value, false)); logger()->debug("Set handling of Qt messages LoggerRepository to %1", QVariant(LogManager::handleQtMessages()).toString()); } } void PropertyConfigurator::configureNonRootElements(const Properties &rProperties, LoggerRepository *pLoggerRepository) { Q_ASSERT_X(pLoggerRepository, "PropertyConfigurator::configureNonRootElements()", "pLoggerRepository must not be null."); const QString logger_prefix = QLatin1String("log4j.logger."); const QString category_prefix = QLatin1String("log4j.category."); // Iterate through all entries: // - Test for the logger/category prefix // - Convert JAVA class names to C++ ones // - Parse logger data (Level, Appender) // - Parse logger additivity QStringList keys = rProperties.propertyNames(); QString key; Q_FOREACH(key, keys) { QString java_name; if (key.startsWith(logger_prefix)) java_name = key.mid(logger_prefix.length()); else if (key.startsWith(category_prefix)) java_name = key.mid(category_prefix.length()); QString cpp_name = OptionConverter::classNameJavaToCpp(java_name); if (!java_name.isEmpty()) { Logger *p_logger = pLoggerRepository->logger(cpp_name); QString value = OptionConverter::findAndSubst(rProperties, key); parseLogger(rProperties, p_logger, key, value); parseAdditivityForLogger(rProperties, p_logger, java_name); } } } void PropertyConfigurator::configureRootLogger(const Properties &rProperties, LoggerRepository *pLoggerRepository) { Q_ASSERT_X(pLoggerRepository, "PropertyConfigurator::configureRootLogger()", "pLoggerRepository must not be null."); const QLatin1String key_root_logger("log4j.rootLogger"); const QLatin1String key_root_category("log4j.rootCategory"); // - Test for the logger/category prefix // - Parse logger data for root logger QString key = key_root_logger; QString value = OptionConverter::findAndSubst(rProperties, key); if (value.isNull()) { key = key_root_category; value = OptionConverter::findAndSubst(rProperties, key); if (!value.isNull()) logger()->warn("[%1] is deprecated. Use [%2] instead.", key_root_category, key_root_logger); } if (value.isNull()) logger()->debug("Could not find root logger information. Is this correct?"); else parseLogger(rProperties, pLoggerRepository->rootLogger(), key, value); } void PropertyConfigurator::parseAdditivityForLogger(const Properties &rProperties, Logger *pLogger, const QString &rLog4jName) const { Q_ASSERT_X(pLogger, "parseAdditivityForLogger()", "pLogger must not be null."); const QLatin1String additivity_prefix("log4j.additivity."); // - Lookup additivity key for logger // - Set additivity, if specified QString key = additivity_prefix + rLog4jName; QString value = OptionConverter::findAndSubst(rProperties, key); logger()->debug("Parsing additivity for logger: key '%1', value '%2'", key, value); if (!value.isEmpty()) { bool additivity = OptionConverter::toBoolean(value, true); logger()->debug("Setting additivity for logger '%1' to '%2'", pLogger->name(), QVariant(value).toString()); pLogger->setAdditivity(additivity); } } LogObjectPtr PropertyConfigurator::parseAppender(const Properties &rProperties, const QString &rName) { // - Test if appender has been parsed before // - Find appender key // - Create appender object // - Set layout, if required by appender // - Set properties // - Activate options // - Add appender to registry const QLatin1String appender_prefix("log4j.appender."); logger()->debug("Parsing appender named '%1'", rName); if (mAppenderRegistry.contains(rName)) { logger()->debug("Appender '%1' was already parsed.", rName); return mAppenderRegistry.value(rName); } QString key = appender_prefix + rName; QString value = OptionConverter::findAndSubst(rProperties, key); if (value.isNull()) { LogError e = LOG4QT_ERROR(QT_TR_NOOP("Missing appender definition for appender named '%1'"), CONFIGURATOR_MISSING_APPENDER_ERROR, "Log4Qt::PropertyConfigurator"); e << rName; logger()->error(e); return 0; } LogObjectPtr p_appender = Factory::createAppender(value); if (!p_appender) { LogError e = LOG4QT_ERROR(QT_TR_NOOP("Unable to create appender of class '%1' namd '%2'"), CONFIGURATOR_UNKNOWN_APPENDER_CLASS_ERROR, "Log4Qt::PropertyConfigurator"); e << value << rName; logger()->error(e); return 0; } p_appender->setName(rName); if (p_appender->requiresLayout()) { LogObjectPtr p_layout = parseLayout(rProperties, key); if (p_layout) p_appender->setLayout(p_layout); else return 0; } QStringList exclusions; exclusions << QLatin1String("layout"); setProperties(rProperties, key + QLatin1String("."), exclusions, p_appender); AppenderSkeleton *p_appenderskeleton = qobject_cast(p_appender); if (p_appenderskeleton) p_appenderskeleton->activateOptions(); mAppenderRegistry.insert(rName, p_appender); return p_appender; } LogObjectPtr PropertyConfigurator::parseLayout(const Properties &rProperties, const QString &rAppenderKey) { Q_ASSERT_X(!rAppenderKey.isEmpty(), "PropertyConfigurator::parseLayout()", "rAppenderKey must not be empty."); // - Find layout key // - Create layput object // - Set properties // - Activate options const QLatin1String layout_suffix(".layout"); logger()->debug("Parsing layout for appender named '%1'", rAppenderKey); QString key = rAppenderKey + layout_suffix; QString value = OptionConverter::findAndSubst(rProperties, key); if (value.isNull()) { LogError e = LOG4QT_ERROR(QT_TR_NOOP("Missing layout definition for appender '%1'"), CONFIGURATOR_MISSING_LAYOUT_ERROR, "Log4Qt::PropertyConfigurator"); e << rAppenderKey; logger()->error(e); return 0; } LogObjectPtr p_layout = Factory::createLayout(value); if (!p_layout) { LogError e = LOG4QT_ERROR(QT_TR_NOOP("Unable to create layoput of class '%1' requested by appender '%2'"), CONFIGURATOR_UNKNOWN_LAYOUT_CLASS_ERROR, "Log4Qt::PropertyConfigurator"); e << value << rAppenderKey; logger()->error(e); return 0; } QStringList exclusions; setProperties(rProperties, key + QLatin1String("."), QStringList(), p_layout); p_layout->activateOptions(); return p_layout; } void PropertyConfigurator::parseLogger(const Properties &rProperties, Logger *pLogger, const QString &rKey, const QString &rValue) { Q_ASSERT_X(pLogger, "PropertyConfigurator::parseLogger()", "pLogger must not be null."); Q_ASSERT_X(!rKey.isEmpty(), "PropertyConfigurator::parseLogger()", "rKey must not be empty."); const QLatin1String keyword_inherited("INHERITED"); // - Split value on comma // - If level value, is specified // - Test for NULL and INHERITED // - Ensure root logger is not set to NULL // - Set level // - For each entry // - Create Appender logger()->debug("Parsing logger: key '%1', value '%2'", rKey, rValue); QStringList appenders = rValue.split(QLatin1Char(',')); QStringListIterator i (appenders); // First entry is the level. There will be always one entry, even if the rValue is // empty or does not contain a comma. QString value = i.next().trimmed(); if (!value.isEmpty()) { Level level; if (value.compare(keyword_inherited,Qt::CaseInsensitive) == 0) level = Level::NULL_INT; else level = OptionConverter::toLevel(value, Level::DEBUG_INT); if (level == Level::NULL_INT && pLogger->name() == QString()) logger()->warn("The root logger level cannot be set to NULL."); else { pLogger->setLevel(level); logger()->debug("Set level for logger '%1' to '%2'", pLogger->name(), pLogger->level().toString()); } } pLogger->removeAllAppenders(); while(i.hasNext()) { value = i.next().trimmed(); if(value.isEmpty()) continue; LogObjectPtr p_appender = parseAppender(rProperties, value); if (p_appender) pLogger->addAppender(p_appender); } } void PropertyConfigurator::setProperties(const Properties &rProperties, const QString &rPrefix, const QStringList &rExclusions, QObject *pObject) { Q_ASSERT_X(!rPrefix.isEmpty(), "PropertyConfigurator::setProperties()", "rPrefix must not be empty."); Q_ASSERT_X(pObject, "PropertyConfigurator::setProperties()", "pObject must not be null."); // Iterate through all entries: // - Test for prefix to determine, if setting is for object // - Skip empty property name // - Skip property names in exclusion list // - Set property on object logger()->debug("Setting properties for object of class '%1' from keys starting with '%2'", QLatin1String(pObject->metaObject()->className()), rPrefix); QStringList keys = rProperties.propertyNames(); QString key; Q_FOREACH(key, keys) { if (!key.startsWith(rPrefix)) continue; QString property = key.mid(rPrefix.length()); if (property.isEmpty()) continue; QStringList split_property = property.split(QLatin1Char('.')); if (rExclusions.contains(split_property.at(0), Qt::CaseInsensitive)) continue; QString value = OptionConverter::findAndSubst(rProperties, key); Factory::setObjectProperty(pObject, property, value); } } void PropertyConfigurator::startCaptureErrors() { Q_ASSERT_X(!mpConfigureErrors, "PropertyConfigurator::startCaptureErrors()", "mpConfigureErrors must be empty."); mpConfigureErrors = new ListAppender; mpConfigureErrors->setName(QLatin1String("PropertyConfigurator")); mpConfigureErrors->setConfiguratorList(true); mpConfigureErrors->setThreshold(Level::ERROR_INT); LogManager::logLogger()->addAppender(mpConfigureErrors); } bool PropertyConfigurator::stopCaptureErrors() { Q_ASSERT_X(mpConfigureErrors, "PropertyConfigurator::stopCaptureErrors()", "mpConfigureErrors must not be empty."); LogManager::logLogger()->removeAppender(mpConfigureErrors); ConfiguratorHelper::setConfigureError(mpConfigureErrors->list()); bool result = (mpConfigureErrors->list().count() == 0); mpConfigureErrors = 0; return result; } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const PropertyConfigurator &rPropertyConfigurator) { Q_UNUSED(rPropertyConfigurator); debug.nospace() << "PropertyConfigurator(" << ")"; return debug.space(); } #endif } // namespace Logging ukui-interface/src/log4qt/log4qt/logger.h0000664000175000017500000017651215167726076017313 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: logger.h * created: September 2007 * author: Martin Heinrich * * * changes: Sep 2008, Martin Heinrich: * - Replaced usage of q_atomic_test_and_set_ptr with * QBasicAtomicPointer * * * Copyright 2007 - 2008 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_LOGGER_H #define LOG4QT_LOGGER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #include #endif #include #include #include "log4qt/helpers/logerror.h" #include "log4qt/helpers/classlogger.h" #include "log4qt/helpers/logobjectptr.h" #include "log4qt/level.h" #include "ukui-logmacros.h" #if QT_VERSION >= 0x040400 && QT_VERSION < 0x060000 # ifndef Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE # warning "QAtomicPointer test and set is not native. The macro Log4Qt::LOG4QT_DECLARE_STATIC_LOGGER is not thread-safe." # endif #endif /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * LOG4QT_DECLARE_STATIC_LOGGER declares a static function \a FUNCTION that * returns a pointer to a \ref Log4Qt::Logger "Logger" named after \a CLASS. * * On the first invocation the \ref Log4Qt::Logger "Logger" is requested * by calling \ref Log4Qt::Logger::logger(const char *pName) * "Logger::logger( #CLASS )". The pointer is stored to be returned on * subsequent invocations. * * The following example shows how to use the macro to define a logger to be * used within a class not derived from QObject. * * \code * #file: counter.h * * #include logger.h * * class Counter * { * public: * Counter(); * Counter(int preset); * private: * int mCount; * } * \endcode * \code * #file: counter.cpp * * #include counter.h * * LOG4QT_DECLARE_STATIC_LOGGER(logger, Counter) * * Counter::Counter() : * mCount(0) * {} * * void Counter::Counter(int preset) : * mCount(preset) * { * if (preset < 0) * { * logger()->warn("Invalid negative counter preset %1. Using 0 instead.", preset); * mCount = 0; * } * } * \endcode * * \note The function created by the macro is thread-safe. * * \sa \ref Log4Qt::Logger::logger(const char *pName) "Logger::logger(const char *pName)" */ #if QT_VERSION < QT_VERSION_CHECK(4, 4, 0) #define LOG4QT_DECLARE_STATIC_LOGGER(FUNCTION, CLASS) \ static Log4Qt::Logger *FUNCTION() \ { \ static Log4Qt::Logger *p_logger = 0; \ if (!p_logger) \ { \ q_atomic_test_and_set_ptr( \ &p_logger, \ 0, \ Log4Qt::Logger::logger( #CLASS )); \ } \ return p_logger; \ } #elif QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #define LOG4QT_DECLARE_STATIC_LOGGER(FUNCTION, CLASS) \ static Log4Qt::Logger *FUNCTION() \ { \ static QBasicAtomicPointer p_logger = \ Q_BASIC_ATOMIC_INITIALIZER(0); \ if (!p_logger) \ { \ p_logger.testAndSetOrdered(0, \ Log4Qt::Logger::logger( #CLASS )); \ } \ return p_logger; \ } #else #define LOG4QT_DECLARE_STATIC_LOGGER(FUNCTION, CLASS) \ static Log4Qt::Logger *FUNCTION() \ { \ static QBasicAtomicPointer p_logger = \ Q_BASIC_ATOMIC_INITIALIZER(0); \ if (!p_logger.loadAcquire()) \ { \ p_logger.testAndSetOrdered(0, \ Log4Qt::Logger::logger( #CLASS )); \ } \ return p_logger.loadAcquire(); \ } #endif /*! * LOG4QT_DECLARE_QCLASS_LOGGER declares member functions to retrieve * \ref Log4Qt::Logger "Logger" for the class it is used in. * * On the first invocation the \ref Log4Qt::Logger "Logger" is requested * by a call to \ref Log4Qt::Logger::logger(const char *pName) * "Logger::logger(const char *pName)". The pointer is stored to be * returned on subsequent invocations. * * The following example shows how to use the macro to define a logger to be * used within a class derived from QObject. * * \code * #file: counter.h * * #include qobject.h * #include logger.h * * class Counter : public QObject * { * Q_OBJECT * LOG4QT_DECLARE_QCLASS_LOGGER * public: * Counter(); * Counter(int preset); * private: * int mCount; * } * \endcode * \code * #file: counter.cpp * * #include counter.h * * Counter::Counter() : * mCount(0) * {} * * void Counter::Counter(int preset) * mCount(preset) * { * if (preset < 0) * { * logger()->warn("Invalid negative counter preset %1. Using 0 instead.", preset); * mCount = 0; * } * } * \endcode * * \note The function created by the macro is thread-safe. * * \sa \ref Log4Qt::Logger::logger(const char *pName) "Logger::logger(const char *pName)", * \ref Log4Qt::ClassLogger "ClassLogger" */ #define LOG4QT_DECLARE_QCLASS_LOGGER \ private: \ mutable Log4Qt::ClassLogger mLog4QtClassLogger; \ public: \ inline Log4Qt::Logger *logger() const \ { return mLog4QtClassLogger.logger(this); } \ private: class Appender; class LoggingEvent; class LoggerRepository; /*! * \brief The class Logger provides logging services. * * A pointer to a logger can be retrieved by calling Logger::logger() or * LogManager::logger() with the class name as argument. Because a logger * is never destroyed it is possible to store the pointer to the logger. * This way the lookup of the pointer in the repository is only required * on the first logging operation. The macros \ref * Log4Qt::LOG4QT_DECLARE_STATIC_LOGGER "LOG4QT_DECLARE_STATIC_LOGGER" and * \ref Log4Qt::LOG4QT_DECLARE_QCLASS_LOGGER "LOG4QT_DECLARE_QCLASS_LOGGER" * provide a thread-safe implementation to store the logger pointer. * * \note All the functions declared in this class are thread-safe. */ class LIBUKUILOG4QT_EXPORT Logger : public QObject { Q_OBJECT /*! * The property holds, if the logger is additive. * * The default is true for being additive. * * \sa additive(), setAdditive() */ Q_PROPERTY(bool additivity READ additivity WRITE setAdditivity) /*! * The property holds the level used by the logger. * * The default is Level::NULL_INT. * \sa level(), setLevel() */ Q_PROPERTY(Level level READ level WRITE setLevel) /*! * The property holds the LoggerRepository of the logger. * * \sa loggerRepository() */ Q_PROPERTY(LoggerRepository* loggerRepository READ loggerRepository) /*! * The property holds the name of the logger. * * \sa name() */ Q_PROPERTY(QString name READ name) /*! * The property holds the parent logger of the logger. * * \sa parentLogger() */ Q_PROPERTY(Logger* parentLogger READ parentLogger) LOG4QT_DECLARE_QCLASS_LOGGER protected: Logger(LoggerRepository* pLoggerRepository, Level level, const QString &rName, Logger *pParent = 0); virtual ~Logger(); private: Logger(const Logger &rOther); // Not implemented Logger &operator=(const Logger &rOther); // Not implemented public: bool additivity() const; QList appenders() const; Level level() const; LoggerRepository *loggerRepository() const; QString name() const; Logger *parentLogger() const; // JAVA: ResourceBundle *resourceBundle() const; // JAVA: void setResourceBundle(ResourceBundle *pResourceBundle); void setAdditivity(bool additivity); virtual void setLevel(Level level); void addAppender(Appender *pAppender); Appender *appender(const QString &rName) const; void callAppenders(const LoggingEvent &rEvent) const; bool isAttached(Appender *pAppender) const; /*! * Removes all appenders that have been previously added from this * Logger. * * To allow configurators to collect events during the configuration * process ListAppenders with the configuratorList property set, will * not be removed. * * \sa LisAppender::setConfiguratorList() */ void removeAllAppenders(); void removeAppender(Appender *pAppender); void removeAppender(const QString &rName); // JAVA: QString resourceBundleString(const QString &rKey) const; Level effectiveLevel() const; bool isDebugEnabled() const; /*! * Checks if this logger is enabled for a given Level \a level. If the * logger is enabled the function returns true. Otherwise it returns * false. * * A logger is enabled for a level, if the level is greater or equal * then the repository threshold and greater and equal then the loggers * effective level. * * \sa LoggerRepository::isDisabled(), effectiveLevel() */ bool isEnabledFor(Level level) const; bool isErrorEnabled() const; bool isFatalEnabled() const; bool isInfoEnabled() const; bool isTraceEnabled() const; bool isWarnEnabled() const; void debug(const QString &rMessage) const; void debug(const LogError &rLogError) const; void debug(const char *pMessage) const; void debug(const char *pMessage, const QString &rArg1) const; void debug(const char *pMessage, int arg1) const; void debug(const char *pMessage, const QString &rArg1, const QString &rArg2) const; void debug(const char *pMessage, const QString &rArg1, int arg2) const; void debug(const char *pMessage, int arg1, const QString &rArg2) const; void debug(const char *pMessage, int arg1, int arg2) const; void debug(const char *pMessage, const QString &rArg1, const QString &rArg2, const QString &rArg3) const; void debug(const char *pMessage, const QString &rArg1, const QString &rArg2, int arg3) const; void debug(const char *pMessage, const QString &rArg1, int arg2, const QString &rArg3) const; void debug(const char *pMessage, const QString &rArg1, int arg2, int arg3) const; void debug(const char *pMessage, int arg1, const QString &rArg2, const QString &rArg3) const; void debug(const char *pMessage, int arg1, const QString &rArg2, int arg3) const; void debug(const char *pMessage, int arg1, int arg2, const QString &rArg3) const; void debug(const char *pMessage, int arg1, int arg2, int arg3) const; void debug(const char *pMessage, const QVariant &rArg1, const QVariant &rArg2, const QVariant &rArg3) const; void error(const QString &rMessage) const; void error(const LogError &rLogError) const; void error(const char *pMessage) const; void error(const char *pMessage, const QString &rArg1) const; void error(const char *pMessage, int arg1) const; void error(const char *pMessage, const QString &rArg1, const QString &rArg2) const; void error(const char *pMessage, const QString &rArg1, int arg2) const; void error(const char *pMessage, int arg1, const QString &rArg2) const; void error(const char *pMessage, int arg1, int arg2) const; void error(const char *pMessage, const QString &rArg1, const QString &rArg2, const QString &rArg3) const; void error(const char *pMessage, const QString &rArg1, const QString &rArg2, int arg3) const; void error(const char *pMessage, const QString &rArg1, int arg2, const QString &rArg3) const; void error(const char *pMessage, const QString &rArg1, int arg2, int arg3) const; void error(const char *pMessage, int arg1, const QString &rArg2, const QString &rArg3) const; void error(const char *pMessage, int arg1, const QString &rArg2, int arg3) const; void error(const char *pMessage, int arg1, int arg2, const QString &rArg3) const; void error(const char *pMessage, int arg1, int arg2, int arg3) const; void error(const char *pMessage, const QVariant &rArg1, const QVariant &rArg2, const QVariant &rArg3) const; void fatal(const QString &rMessage) const; void fatal(const LogError &rLogError) const; void fatal(const char *pMessage) const; void fatal(const char *pMessage, const QString &rArg1) const; void fatal(const char *pMessage, int arg1) const; void fatal(const char *pMessage, const QString &rArg1, const QString &rArg2) const; void fatal(const char *pMessage, const QString &rArg1, int arg2) const; void fatal(const char *pMessage, int arg1, const QString &rArg2) const; void fatal(const char *pMessage, int arg1, int arg2) const; void fatal(const char *pMessage, const QString &rArg1, const QString &rArg2, const QString &rArg3) const; void fatal(const char *pMessage, const QString &rArg1, const QString &rArg2, int arg3) const; void fatal(const char *pMessage, const QString &rArg1, int arg2, const QString &rArg3) const; void fatal(const char *pMessage, const QString &rArg1, int arg2, int arg3) const; void fatal(const char *pMessage, int arg1, const QString &rArg2, const QString &rArg3) const; void fatal(const char *pMessage, int arg1, const QString &rArg2, int arg3) const; void fatal(const char *pMessage, int arg1, int arg2, const QString &rArg3) const; void fatal(const char *pMessage, int arg1, int arg2, int arg3) const; void fatal(const char *pMessage, const QVariant &rArg1, const QVariant &rArg2, const QVariant &rArg3) const; void info(const QString &rMessage) const; void info(const LogError &rLogError) const; void info(const char *pMessage) const; void info(const char *pMessage, const QString &rArg1) const; void info(const char *pMessage, int arg1) const; void info(const char *pMessage, const QString &rArg1, const QString &rArg2) const; void info(const char *pMessage, const QString &rArg1, int arg2) const; void info(const char *pMessage, int arg1, const QString &rArg2) const; void info(const char *pMessage, int arg1, int arg2) const; void info(const char *pMessage, const QString &rArg1, const QString &rArg2, const QString &rArg3) const; void info(const char *pMessage, const QString &rArg1, const QString &rArg2, int arg3) const; void info(const char *pMessage, const QString &rArg1, int arg2, const QString &rArg3) const; void info(const char *pMessage, const QString &rArg1, int arg2, int arg3) const; void info(const char *pMessage, int arg1, const QString &rArg2, const QString &rArg3) const; void info(const char *pMessage, int arg1, const QString &rArg2, int arg3) const; void info(const char *pMessage, int arg1, int arg2, const QString &rArg3) const; void info(const char *pMessage, int arg1, int arg2, int arg3) const; void info(const char *pMessage, const QVariant &rArg1, const QVariant &rArg2, const QVariant &rArg3) const; void log(Level level, const QString &rMessage) const; void log(Level level, const LogError &rLogError) const; void log(Level level, const char *pMessage) const; void log(Level level, const char *pMessage, const QString &rArg1) const; void log(Level level, const char *pMessage, int arg1) const; void log(Level level, const char *pMessage, const QString &rArg1, const QString &rArg2) const; void log(Level level, const char *pMessage, const QString &rArg1, int arg2) const; void log(Level level, const char *pMessage, int arg1, const QString &rArg2) const; void log(Level level, const char *pMessage, int arg1, int arg2) const; void log(Level level, const char *pMessage, const QString &rArg1, const QString &rArg2, const QString &rArg3) const; void log(Level level, const char *pMessage, const QString &rArg1, const QString &rArg2, int arg3) const; void log(Level level, const char *pMessage, const QString &rArg1, int arg2, const QString &rArg3) const; void log(Level level, const char *pMessage, const QString &rArg1, int arg2, int arg3) const; void log(Level level, const char *pMessage, int arg1, const QString &rArg2, const QString &rArg3) const; void log(Level level, const char *pMessage, int arg1, const QString &rArg2, int arg3) const; void log(Level level, const char *pMessage, int arg1, int arg2, const QString &rArg3) const; void log(Level level, const char *pMessage, int arg1, int arg2, int arg3) const; void log(Level level, const char *pMessage, const QVariant &rArg1, const QVariant &rArg2, const QVariant &rArg3) const; // JAVA: void l7dlog(Level level, // const QString &rKey); // JAVA: void l7dlog(Level level, // const QString &rKey, // const QList rParameters); void trace(const QString &rMessage) const; void trace(const LogError &rLogError) const; void trace(const char *pMessage) const; void trace(const char *pMessage, const QString &rArg1) const; void trace(const char *pMessage, int arg1) const; void trace(const char *pMessage, const QString &rArg1, const QString &rArg2) const; void trace(const char *pMessage, const QString &rArg1, int arg2) const; void trace(const char *pMessage, int arg1, const QString &rArg2) const; void trace(const char *pMessage, int arg1, int arg2) const; void trace(const char *pMessage, const QString &rArg1, const QString &rArg2, const QString &rArg3) const; void trace(const char *pMessage, const QString &rArg1, const QString &rArg2, int arg3) const; void trace(const char *pMessage, const QString &rArg1, int arg2, const QString &rArg3) const; void trace(const char *pMessage, const QString &rArg1, int arg2, int arg3) const; void trace(const char *pMessage, int arg1, const QString &rArg2, const QString &rArg3) const; void trace(const char *pMessage, int arg1, const QString &rArg2, int arg3) const; void trace(const char *pMessage, int arg1, int arg2, const QString &rArg3) const; void trace(const char *pMessage, int arg1, int arg2, int arg3) const; void trace(const char *pMessage, const QVariant &rArg1, const QVariant &rArg2, const QVariant &rArg3) const; void warn(const QString &rMessage) const; void warn(const LogError &rLogError) const; void warn(const char *pMessage) const; void warn(const char *pMessage, const QString &rArg1) const; void warn(const char *pMessage, int arg1) const; void warn(const char *pMessage, const QString &rArg1, const QString &rArg2) const; void warn(const char *pMessage, const QString &rArg1, int arg2) const; void warn(const char *pMessage, int arg1, const QString &rArg2) const; void warn(const char *pMessage, int arg1, int arg2) const; void warn(const char *pMessage, const QString &rArg1, const QString &rArg2, const QString &rArg3) const; void warn(const char *pMessage, const QString &rArg1, const QString &rArg2, int arg3) const; void warn(const char *pMessage, const QString &rArg1, int arg2, const QString &rArg3) const; void warn(const char *pMessage, const QString &rArg1, int arg2, int arg3) const; void warn(const char *pMessage, int arg1, const QString &rArg2, const QString &rArg3) const; void warn(const char *pMessage, int arg1, const QString &rArg2, int arg3) const; void warn(const char *pMessage, int arg1, int arg2, const QString &rArg3) const; void warn(const char *pMessage, int arg1, int arg2, int arg3) const; void warn(const char *pMessage, const QVariant &rArg1, const QVariant &rArg2, const QVariant &rArg3) const; // LogManager operations static Logger *logger(const QString &rName); static Logger *logger(const char *pName); static Logger *rootLogger(); signals: void logOutput(); protected: #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream \a rDebug * and returns the stream. * * * %Logger(name:"Log4Qt" appenders:0 additivity:true Level("NULL") * parentLogger: "root" ) * * \sa QDebug, operator<<(QDebug debug, const Appender &rAppender) */ virtual QDebug debug(QDebug &rDebug) const; friend QDebug operator<<(QDebug debug, const Logger &rLogger); #endif // QT_NO_DEBUG_STREAM void forcedLog(Level level, const QString &rMessage) const; protected: mutable QReadWriteLock mObjectGuard; private: const QString mName; LoggerRepository* mpLoggerRepository; volatile bool mAdditivity; QList< LogObjectPtr > mAppenders; Level mLevel; Logger *mpParent; // Needs to be friend to create Logger objects friend class Hierarchy; }; /****************************************************************************** * Operators, Helper ******************************************************************************/ #ifndef QT_NO_DEBUG_STREAM /*! * \relates Logger * * Writes all object member variables to the given debug stream \a debug and * returns the stream. * * To handle subclassing the function uses the virtual member function debug(). * This allows each class to generate its own output. * * \sa QDebug, debug() */ QDebug operator<<(QDebug debug, const Logger &rLogger); #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Inline **************************************************************************/ inline bool Logger::additivity() const { // QReadLocker locker(&mObjectGuard); // Read/Write of int is safe return mAdditivity; } inline Level Logger::level() const { // QReadLocker locker(&mObjectGuard); // Level is thread-safe return mLevel; } inline LoggerRepository *Logger::loggerRepository() const { // QReadLocker locker(&mObjectGuard); // Constant for object lifetime return mpLoggerRepository; } inline QString Logger::name() const { // QReadLocker locker(&mObjectGuard); // Constant for object lifetime return mName; } inline Logger *Logger::parentLogger() const { // QReadLocker locker(&mObjectGuard); // Constant for object lifetime return mpParent; } inline void Logger::setAdditivity(bool additivity) { // QWriteLocker locker(&mObjectGuard); // Read/Write of int is safe mAdditivity = additivity; } // Level operations inline bool Logger::isDebugEnabled() const { return isEnabledFor(Level::DEBUG_INT); } inline bool Logger::isErrorEnabled() const { return isEnabledFor(Level::ERROR_INT); } inline bool Logger::isFatalEnabled() const { return isEnabledFor(Level::FATAL_INT); } inline bool Logger::isInfoEnabled() const { return isEnabledFor(Level::INFO_INT); } inline bool Logger::isTraceEnabled() const { return isEnabledFor(Level::TRACE_INT); } inline bool Logger::isWarnEnabled() const { return isEnabledFor(Level::WARN_INT); } // Log operations: debug inline void Logger::debug(const LogError &rLogError) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, rLogError.toString()); } inline void Logger::debug(const QString &rMessage) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, rMessage); } inline void Logger::debug(const char *pMessage) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage)); } inline void Logger::debug(const char *pMessage, const QString &rArg1) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage).arg(rArg1)); } inline void Logger::debug(const char *pMessage, int arg1) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage).arg(arg1)); } inline void Logger::debug(const char *pMessage, const QString &rArg1, const QString &rArg2) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2)); } inline void Logger::debug(const char *pMessage, const QString &rArg1, int arg2) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2)); } inline void Logger::debug(const char *pMessage, int arg1, const QString &rArg2) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2)); } inline void Logger::debug(const char *pMessage, int arg1, int arg2) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2)); } inline void Logger::debug(const char *pMessage, const QString &rArg1, const QString &rArg2, const QString &rArg3) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2, rArg3)); } inline void Logger::debug(const char *pMessage, const QString &rArg1, const QString &rArg2, int arg3) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2).arg(arg3)); } inline void Logger::debug(const char *pMessage, const QString &rArg1, int arg2, const QString &rArg3) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2).arg(rArg3)); } inline void Logger::debug(const char *pMessage, const QString &rArg1, int arg2, int arg3) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2).arg(arg3)); } inline void Logger::debug(const char *pMessage, int arg1, const QString &rArg2, const QString &rArg3) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2).arg(rArg3)); } inline void Logger::debug(const char *pMessage, int arg1, const QString &rArg2, int arg3) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2).arg(arg3)); } inline void Logger::debug(const char *pMessage, int arg1, int arg2, const QString &rArg3) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2).arg(rArg3)); } inline void Logger::debug(const char *pMessage, int arg1, int arg2, int arg3) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2).arg(arg3)); } inline void Logger::debug(const char *pMessage, const QVariant &rArg1, const QVariant &rArg2, const QVariant &rArg3) const { if (isEnabledFor(Level::DEBUG_INT)) forcedLog(Level::DEBUG_INT, QString::fromUtf8(pMessage).arg(rArg1.toString(), rArg2.toString(), rArg3.toString())); } // Log operations: error inline void Logger::error(const QString &rMessage) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, rMessage); } inline void Logger::error(const LogError &rLogError) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, rLogError.toString()); } inline void Logger::error(const char *pMessage) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage)); } inline void Logger::error(const char *pMessage, const QString &rArg1) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage).arg(rArg1)); } inline void Logger::error(const char *pMessage, int arg1) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage).arg(arg1)); } inline void Logger::error(const char *pMessage, const QString &rArg1, const QString &rArg2) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2)); } inline void Logger::error(const char *pMessage, const QString &rArg1, int arg2) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2)); } inline void Logger::error(const char *pMessage, int arg1, const QString &rArg2) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2)); } inline void Logger::error(const char *pMessage, int arg1, int arg2) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2)); } inline void Logger::error(const char *pMessage, const QString &rArg1, const QString &rArg2, const QString &rArg3) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2, rArg3)); } inline void Logger::error(const char *pMessage, const QString &rArg1, const QString &rArg2, int arg3) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2).arg(arg3)); } inline void Logger::error(const char *pMessage, const QString &rArg1, int arg2, const QString &rArg3) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2).arg(rArg3)); } inline void Logger::error(const char *pMessage, const QString &rArg1, int arg2, int arg3) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2).arg(arg3)); } inline void Logger::error(const char *pMessage, int arg1, const QString &rArg2, const QString &rArg3) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2).arg(rArg3)); } inline void Logger::error(const char *pMessage, int arg1, const QString &rArg2, int arg3) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2).arg(arg3)); } inline void Logger::error(const char *pMessage, int arg1, int arg2, const QString &rArg3) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2).arg(rArg3)); } inline void Logger::error(const char *pMessage, int arg1, int arg2, int arg3) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2).arg(arg3)); } inline void Logger::error(const char *pMessage, const QVariant &rArg1, const QVariant &rArg2, const QVariant &rArg3) const { if (isEnabledFor(Level::ERROR_INT)) forcedLog(Level::ERROR_INT, QString::fromUtf8(pMessage).arg(rArg1.toString(), rArg2.toString(), rArg3.toString())); } // Log operations: fatal inline void Logger::fatal(const QString &rMessage) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, rMessage); } inline void Logger::fatal(const LogError &rLogError) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, rLogError.toString()); } inline void Logger::fatal(const char *pMessage) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage)); } inline void Logger::fatal(const char *pMessage, const QString &rArg1) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage).arg(rArg1)); } inline void Logger::fatal(const char *pMessage, int arg1) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage).arg(arg1)); } inline void Logger::fatal(const char *pMessage, const QString &rArg1, const QString &rArg2) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2)); } inline void Logger::fatal(const char *pMessage, const QString &rArg1, int arg2) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2)); } inline void Logger::fatal(const char *pMessage, int arg1, const QString &rArg2) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2)); } inline void Logger::fatal(const char *pMessage, int arg1, int arg2) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2)); } inline void Logger::fatal(const char *pMessage, const QString &rArg1, const QString &rArg2, const QString &rArg3) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2, rArg3)); } inline void Logger::fatal(const char *pMessage, const QString &rArg1, const QString &rArg2, int arg3) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2).arg(arg3)); } inline void Logger::fatal(const char *pMessage, const QString &rArg1, int arg2, const QString &rArg3) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2).arg(rArg3)); } inline void Logger::fatal(const char *pMessage, const QString &rArg1, int arg2, int arg3) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2).arg(arg3)); } inline void Logger::fatal(const char *pMessage, int arg1, const QString &rArg2, const QString &rArg3) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2).arg(rArg3)); } inline void Logger::fatal(const char *pMessage, int arg1, const QString &rArg2, int arg3) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2).arg(arg3)); } inline void Logger::fatal(const char *pMessage, int arg1, int arg2, const QString &rArg3) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2).arg(rArg3)); } inline void Logger::fatal(const char *pMessage, int arg1, int arg2, int arg3) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2).arg(arg3)); } inline void Logger::fatal(const char *pMessage, const QVariant &rArg1, const QVariant &rArg2, const QVariant &rArg3) const { if (isEnabledFor(Level::FATAL_INT)) forcedLog(Level::FATAL_INT, QString::fromUtf8(pMessage).arg(rArg1.toString(), rArg2.toString(), rArg3.toString())); } // Log operations: info inline void Logger::info(const QString &rMessage) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, rMessage); } inline void Logger::info(const LogError &rLogError) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, rLogError.toString()); } inline void Logger::info(const char *pMessage) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage)); } inline void Logger::info(const char *pMessage, const QString &rArg1) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage).arg(rArg1)); } inline void Logger::info(const char *pMessage, int arg1) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage).arg(arg1)); } inline void Logger::info(const char *pMessage, const QString &rArg1, const QString &rArg2) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2)); } inline void Logger::info(const char *pMessage, const QString &rArg1, int arg2) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2)); } inline void Logger::info(const char *pMessage, int arg1, const QString &rArg2) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2)); } inline void Logger::info(const char *pMessage, int arg1, int arg2) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2)); } inline void Logger::info(const char *pMessage, const QString &rArg1, const QString &rArg2, const QString &rArg3) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2, rArg3)); } inline void Logger::info(const char *pMessage, const QString &rArg1, const QString &rArg2, int arg3) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2).arg(arg3)); } inline void Logger::info(const char *pMessage, const QString &rArg1, int arg2, const QString &rArg3) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2).arg(rArg3)); } inline void Logger::info(const char *pMessage, const QString &rArg1, int arg2, int arg3) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2).arg(arg3)); } inline void Logger::info(const char *pMessage, int arg1, const QString &rArg2, const QString &rArg3) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2).arg(rArg3)); } inline void Logger::info(const char *pMessage, int arg1, const QString &rArg2, int arg3) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2).arg(arg3)); } inline void Logger::info(const char *pMessage, int arg1, int arg2, const QString &rArg3) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2).arg(rArg3)); } inline void Logger::info(const char *pMessage, int arg1, int arg2, int arg3) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2).arg(arg3)); } inline void Logger::info(const char *pMessage, const QVariant &rArg1, const QVariant &rArg2, const QVariant &rArg3) const { if (isEnabledFor(Level::INFO_INT)) forcedLog(Level::INFO_INT, QString::fromUtf8(pMessage).arg(rArg1.toString(), rArg2.toString(), rArg3.toString())); } // Log operations: log inline void Logger::log(Level level, const QString &rMessage) const { if (isEnabledFor(level)) forcedLog(level, rMessage); } inline void Logger::log(Level level, const LogError &rLogError) const { if (isEnabledFor(level)) forcedLog(level, rLogError.toString()); } inline void Logger::log(Level level, const char *pMessage) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage)); } inline void Logger::log(Level level, const char *pMessage, const QString &rArg1) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage).arg(rArg1)); } inline void Logger::log(Level level, const char *pMessage, int arg1) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage).arg(arg1)); } inline void Logger::log(Level level, const char *pMessage, const QString &rArg1, const QString &rArg2) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage).arg(rArg1, rArg2)); } inline void Logger::log(Level level, const char *pMessage, const QString &rArg1, int arg2) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2)); } inline void Logger::log(Level level, const char *pMessage, int arg1, const QString &rArg2) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2)); } inline void Logger::log(Level level, const char *pMessage, int arg1, int arg2) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage).arg(arg1).arg(arg2)); } inline void Logger::log(Level level, const char *pMessage, const QString &rArg1, const QString &rArg2, const QString &rArg3) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage).arg(rArg1, rArg2, rArg3)); } inline void Logger::log(Level level, const char *pMessage, const QString &rArg1, const QString &rArg2, int arg3) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage).arg(rArg1, rArg2).arg(arg3)); } inline void Logger::log(Level level, const char *pMessage, const QString &rArg1, int arg2, const QString &rArg3) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2).arg(rArg3)); } inline void Logger::log(Level level, const char *pMessage, const QString &rArg1, int arg2, int arg3) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2).arg(arg3)); } inline void Logger::log(Level level, const char *pMessage, int arg1, const QString &rArg2, const QString &rArg3) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2).arg(rArg3)); } inline void Logger::log(Level level, const char *pMessage, int arg1, const QString &rArg2, int arg3) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2).arg(arg3)); } inline void Logger::log(Level level, const char *pMessage, int arg1, int arg2, const QString &rArg3) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage).arg(arg1).arg(arg2).arg(rArg3)); } inline void Logger::log(Level level, const char *pMessage, int arg1, int arg2, int arg3) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage).arg(arg1).arg(arg2).arg(arg3)); } inline void Logger::log(Level level, const char *pMessage, const QVariant &rArg1, const QVariant &rArg2, const QVariant &rArg3) const { if (isEnabledFor(level)) forcedLog(level, QString::fromUtf8(pMessage).arg(rArg1.toString(), rArg2.toString(), rArg3.toString())); } // Log operations: trace inline void Logger::trace(const QString &rMessage) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, rMessage); } inline void Logger::trace(const LogError &rLogError) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, rLogError.toString()); } inline void Logger::trace(const char *pMessage) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage)); } inline void Logger::trace(const char *pMessage, const QString &rArg1) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage).arg(rArg1)); } inline void Logger::trace(const char *pMessage, int arg1) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage).arg(arg1)); } inline void Logger::trace(const char *pMessage, const QString &rArg1, const QString &rArg2) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2)); } inline void Logger::trace(const char *pMessage, const QString &rArg1, int arg2) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2)); } inline void Logger::trace(const char *pMessage, int arg1, const QString &rArg2) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2)); } inline void Logger::trace(const char *pMessage, int arg1, int arg2) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2)); } inline void Logger::trace(const char *pMessage, const QString &rArg1, const QString &rArg2, const QString &rArg3) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2, rArg3)); } inline void Logger::trace(const char *pMessage, const QString &rArg1, const QString &rArg2, int arg3) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2).arg(arg3)); } inline void Logger::trace(const char *pMessage, const QString &rArg1, int arg2, const QString &rArg3) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2).arg(rArg3)); } inline void Logger::trace(const char *pMessage, const QString &rArg1, int arg2, int arg3) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2).arg(arg3)); } inline void Logger::trace(const char *pMessage, int arg1, const QString &rArg2, const QString &rArg3) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2).arg(rArg3)); } inline void Logger::trace(const char *pMessage, int arg1, const QString &rArg2, int arg3) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2).arg(arg3)); } inline void Logger::trace(const char *pMessage, int arg1, int arg2, const QString &rArg3) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2).arg(rArg3)); } inline void Logger::trace(const char *pMessage, int arg1, int arg2, int arg3) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2).arg(arg3)); } inline void Logger::trace(const char *pMessage, const QVariant &rArg1, const QVariant &rArg2, const QVariant &rArg3) const { if (isEnabledFor(Level::TRACE_INT)) forcedLog(Level::TRACE_INT, QString::fromUtf8(pMessage).arg(rArg1.toString(), rArg2.toString(), rArg3.toString())); } // Log operations: warn inline void Logger::warn(const QString &rMessage) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, rMessage); } inline void Logger::warn(const LogError &rLogError) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, rLogError.toString()); } inline void Logger::warn(const char *pMessage) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage)); } inline void Logger::warn(const char *pMessage, const QString &rArg1) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage).arg(rArg1)); } inline void Logger::warn(const char *pMessage, int arg1) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage).arg(arg1)); } inline void Logger::warn(const char *pMessage, const QString &rArg1, const QString &rArg2) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2)); } inline void Logger::warn(const char *pMessage, const QString &rArg1, int arg2) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2)); } inline void Logger::warn(const char *pMessage, int arg1, const QString &rArg2) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2)); } inline void Logger::warn(const char *pMessage, int arg1, int arg2) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2)); } inline void Logger::warn(const char *pMessage, const QString &rArg1, const QString &rArg2, const QString &rArg3) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2, rArg3)); } inline void Logger::warn(const char *pMessage, const QString &rArg1, const QString &rArg2, int arg3) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage).arg(rArg1, rArg2).arg(arg3)); } inline void Logger::warn(const char *pMessage, const QString &rArg1, int arg2, const QString &rArg3) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2).arg(rArg3)); } inline void Logger::warn(const char *pMessage, const QString &rArg1, int arg2, int arg3) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage).arg(rArg1).arg(arg2).arg(arg3)); } inline void Logger::warn(const char *pMessage, int arg1, const QString &rArg2, const QString &rArg3) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2).arg(rArg3)); } inline void Logger::warn(const char *pMessage, int arg1, const QString &rArg2, int arg3) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage).arg(arg1).arg(rArg2).arg(arg3)); } inline void Logger::warn(const char *pMessage, int arg1, int arg2, const QString &rArg3) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2).arg(rArg3)); } inline void Logger::warn(const char *pMessage, int arg1, int arg2, int arg3) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage).arg(arg1).arg(arg2).arg(arg3)); } inline void Logger::warn(const char *pMessage, const QVariant &rArg1, const QVariant &rArg2, const QVariant &rArg3) const { if (isEnabledFor(Level::WARN_INT)) forcedLog(Level::WARN_INT, QString::fromUtf8(pMessage).arg(rArg1.toString(), rArg2.toString(), rArg3.toString())); } } // namespace Log4Qt // Q_DECLARE_TYPEinfo(Log4Qt::Logger, Q_COMPLEX_TYPE); // Use default // Qt6 compatibility: declare opaque pointers for incomplete types #if QT_VERSION >= 0x060000 Q_DECLARE_OPAQUE_POINTER(Log4Qt::LoggerRepository*) Q_DECLARE_OPAQUE_POINTER(Log4Qt::Logger*) #endif #endif // LOG4QT_LOGGER_H ukui-interface/src/log4qt/log4qt/basicconfigurator.cpp0000664000175000017500000000637715167726064022071 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: basicconfigurator.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/basicconfigurator.h" #include #include #include #include "log4qt/consoleappender.h" #include "log4qt/helpers/configuratorhelper.h" #include "log4qt/helpers/logobjectptr.h" #include "log4qt/logmanager.h" #include "log4qt/patternlayout.h" #include "log4qt/varia/listappender.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: BasicConfigurator **************************************************************************/ bool BasicConfigurator::configure() { LogObjectPtr list = new ListAppender; list->setName(QLatin1String("BasicConfigurator")); list->setConfiguratorList(true); list->setThreshold(Level::ERROR_INT); LogManager::logLogger()->addAppender(list); PatternLayout *p_layout = new PatternLayout(PatternLayout::TTCC_CONVERSION_PATTERN); p_layout->setName(QLatin1String("BasicConfigurator TTCC")); p_layout->activateOptions(); ConsoleAppender *p_appender = new ConsoleAppender(p_layout, ConsoleAppender::STDOUT_TARGET); p_appender->setName(QLatin1String("BasicConfigurator stdout")); p_appender->activateOptions(); LogManager::rootLogger()->addAppender(p_appender); LogManager::logLogger()->removeAppender(list); ConfiguratorHelper::setConfigureError(list->list()); return (list->list().count() == 0); } void BasicConfigurator::configure(Appender *pAppender) { LogManager::rootLogger()->addAppender(pAppender); } void BasicConfigurator::resetConfiguration() { LogManager::resetConfiguration(); } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/layout.cpp0000664000175000017500000000452215167726064017670 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: layout.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/layout.h" #include #include "log4qt/loggingevent.h" #include "log4qt/logmanager.h" namespace Log4Qt { /*************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: Layout **************************************************************************/ QString Layout::contentType() const { return QString::fromLatin1("text/plain"); } void Layout::activateOptions() { } QString Layout::endOfLine() { // There seams to be no function in Qt for this #ifdef Q_OS_WIN32 return QLatin1String("\r\n"); #endif // Q_OS_WIN32 //#ifdef Q_OS_MAC // return QLatin1String("\r"); //#endif // Q_OS_MAC return QLatin1String("\n"); } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/ttcclayout.h0000664000175000017500000001617215167726064020217 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: ttcclayout.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_TTCCLAYOUT_H #define LOG4QT_TTCCLAYOUT_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/layout.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { class LoggingEvent; class PatternFormatter; /*! * \brief The class TTCCLayout outputs the time, thread, logger and nested * diagnostic context information of a logging event. * * \note The ownership and lifetime of objects of this class are managed. * See \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT TTCCLayout : public Layout { Q_OBJECT /*! * The property holds if the logger name is part of the formatted output. * * The default value is true for including the logger name. * * \sa categoryPrefixing(), setCategoryPrefixing() */ Q_PROPERTY(bool categoryPrefixing READ categoryPrefixing WRITE setCategoryPrefixing) /*! * The property holds if the nested context information is part of the * formatted output. * * The default value it true for including the nested context information. * * \sa contextPrinting(), setContextPrinting() */ Q_PROPERTY(bool contextPrinting READ contextPrinting WRITE setContextPrinting) /*! * The property holds the date format used by the layout. * * The default date format is "TIME_RELATIVE". * * \sa dateFormat(), setDateFormat() */ Q_PROPERTY(QString dateFormat READ dateFormat WRITE setDateFormat) /*! * The property holds if the thread name is part of the formatted output. * * The default value it true for including the thread name. * * \sa threadPrinting(), setThreadPrinting() */ Q_PROPERTY(bool threadPrinting READ threadPrinting WRITE setThreadPrinting) public: /*! * The enum DateFormat defines constants for date formats. * * \sa setDateFormat(DateFormat), DateTime::toString() */ enum DateFormat { /*! The none date format string is "NONE". */ NONE, /*! * The iso8601 date format string is "ISO8601". The date will be * formatted as yyyy-MM-dd hh:mm:ss.zzz. */ ISO8601, /*! * The absolute date format string is "TIME_ABSOLUTE". The date will be * formatted as HH:mm:ss.zzz. */ TIME_ABSOLUTE, /*! * The date date format string is "DATE". The date will be formatted * as MMM YYYY HH:mm:ss.zzzz. */ DATE, /*! * The relative date format string is "TIME_RELATIVE". The date will be * formatted as milliseconds since start of the program. */ TIME_RELATIVE }; Q_ENUMS(DateFormat) TTCCLayout(QObject *pParent = 0); TTCCLayout(const QString &rDateFormat, QObject *pParent = 0); /*! * Creates a TTCCLayout with the date formar value specified by * the \a dateFormat constant and the parent \a pParent. */ TTCCLayout(DateFormat dateFormat, QObject *pParent = 0); virtual ~TTCCLayout(); private: TTCCLayout(const TTCCLayout &rOther); // Not implemented TTCCLayout &operator=(const TTCCLayout &rOther); // Not implemented public: bool categoryPrefixing() const; bool contextPrinting() const; QString dateFormat() const; // JAVA: bool ignoresThrowable() const; bool threadPrinting() const; void setCategoryPrefixing(bool categoryPrefixing); void setContextPrinting(bool contextPrinting); void setDateFormat(const QString &rDateFormat); /*! * Sets the date format to the value specified by the \a dateFormat * constant. */ void setDateFormat(DateFormat dateFormat); // JAVA: setIgnoresThrowable(bool ignoresThrowable); void setThreadPrinting(bool threadPrinting); virtual QString format(const LoggingEvent &rEvent); protected: #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream * \a rDebug and returns the stream. * * * %TTCCLayout(name:"TTCC" categoryprefixing:true * contextprinting:true dateformat:"ISO8601" * referencecount:1 threadprinting:true) * * \sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const; #endif // QT_NO_DEBUG_STREAM private: void updatePatternFormatter(); private: bool mCategoryPrefixing; bool mContextPrinting; QString mDateFormat; bool mThreadPrinting; PatternFormatter *mpPatternFormatter; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline bool TTCCLayout::categoryPrefixing() const { return mCategoryPrefixing; } inline bool TTCCLayout::contextPrinting() const { return mContextPrinting; } inline QString TTCCLayout::dateFormat() const { return mDateFormat; } inline bool TTCCLayout::threadPrinting() const { return mThreadPrinting; } inline void TTCCLayout::setCategoryPrefixing(bool categoryPrefixing) { mCategoryPrefixing = categoryPrefixing; updatePatternFormatter(); } inline void TTCCLayout::setContextPrinting(bool contextPrinting) { mContextPrinting = contextPrinting; updatePatternFormatter(); } inline void TTCCLayout::setDateFormat(const QString &rDateFormat) { mDateFormat = rDateFormat; updatePatternFormatter(); } inline void TTCCLayout::setThreadPrinting(bool threadPrinting) { mThreadPrinting = threadPrinting; updatePatternFormatter(); } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::TTCCLayout, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_TTCCLAYOUT_H ukui-interface/src/log4qt/log4qt/ttcclayout.cpp0000664000175000017500000001150115167726064020541 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: ttcclayout.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/ttcclayout.h" #include #include #include "log4qt/helpers/datetime.h" #include "log4qt/helpers/patternformatter.h" #include "log4qt/logger.h" #include "log4qt/loggingevent.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: TTCCLayout **************************************************************************/ TTCCLayout::TTCCLayout(QObject *pParent) : Layout(pParent), mCategoryPrefixing(true), mContextPrinting(true), mDateFormat(), mThreadPrinting(true), mpPatternFormatter(0) { setDateFormat(TIME_RELATIVE); } TTCCLayout::TTCCLayout(const QString &rDateFormat, QObject *pParent) : Layout(pParent), mCategoryPrefixing(true), mContextPrinting(true), mDateFormat(rDateFormat), mThreadPrinting(true), mpPatternFormatter(0) { } TTCCLayout::TTCCLayout(DateFormat dateFormat, QObject *pParent) : Layout(pParent), mCategoryPrefixing(true), mContextPrinting(true), mDateFormat(), mThreadPrinting(true), mpPatternFormatter(0) { setDateFormat(dateFormat); } TTCCLayout::~TTCCLayout() { delete mpPatternFormatter; } void TTCCLayout::setDateFormat(DateFormat dateFormat) { switch (dateFormat) { case NONE: setDateFormat(QLatin1String("NONE")); break; case ISO8601: setDateFormat(QLatin1String("ISO8601")); break; case TIME_ABSOLUTE: setDateFormat(QLatin1String("TIME_ABSOLUTE")); break; case DATE: setDateFormat(QLatin1String("DATE")); break; case TIME_RELATIVE: setDateFormat(QLatin1String("TIME_RELATIVE")); break; default: Q_ASSERT_X(false, "TTCCLayout::setDateFormat", "Unkown DateFormat"); setDateFormat(QString()); } } QString TTCCLayout::format(const LoggingEvent &rEvent) { Q_ASSERT_X(mpPatternFormatter, "TTCCLayout::format()", "mpPatternConverter must not be null"); return mpPatternFormatter->format(rEvent); } void TTCCLayout::updatePatternFormatter() { QString pattern; pattern += QLatin1String("%d{") + mDateFormat + QLatin1String("}"); if (mThreadPrinting) pattern += QLatin1String(" [%t]"); pattern += QLatin1String(" %-5p"); if (mCategoryPrefixing) pattern += QLatin1String(" %c"); if (mContextPrinting) pattern += QLatin1String(" %x"); pattern += QLatin1String(" - %m%n"); delete mpPatternFormatter; mpPatternFormatter = new PatternFormatter(pattern); } #ifndef QT_NO_DEBUG_STREAM QDebug TTCCLayout::debug(QDebug &rDebug) const { rDebug.nospace() << "TTCCLayout(" << "name:" << name() << " " << "categoryprefixing:" << categoryPrefixing() << " " << "contextprinting:" << contextPrinting() << " " << "dateformat:" << dateFormat() << " " << "referencecount:" << referenceCount() << " " << "threadprinting:" << threadPrinting() << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/helpers/0000775000175000017500000000000015167726076017311 5ustar fengfengukui-interface/src/log4qt/log4qt/helpers/properties.h0000664000175000017500000001240715167726064021657 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: properties.h * created: September * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_PROPERTIES_H #define LOG4QT_PROPERTIES_H #include "ukui-logmacros.h" /****************************************************************************** * Dependencies ******************************************************************************/ #include #include /****************************************************************************** * Declarations ******************************************************************************/ class QIODevice; class QSettings; namespace Log4Qt { /*! * \brief The class Properties implements a JAVA property hash. */ class LIBUKUILOG4QT_EXPORT Properties : public QHash { public: Properties(Properties *pDefaultProperties = 0); // virtual ~Properties(); // Use compiler default // Properties(const Properties &rOther); // Use compiler default // Properties &operator=(const Properties &rOther); // Not implemented public: Properties *defaultProperties() const; QString property(const QString &rKey) const; QString property(const QString &rKey, const QString &rDefaultValue) const; void setDefaultProperties(Properties *pDefault); void setProperty(const QString &rKey, const QString &rValue); // JAVA: void list(QTextStream &rTextStream); void load(QIODevice *pDevice); /*! * Reads all child keys from the QSettings object \a rSettings and * inserts them into this object. The value is created using * QVariant::toString(). Types that do not support toString() are * resulting in an empty string. * * \code * QSettings settings; * settings.setValue("Package", "Full"); * settings.setValue("Background", Qt::white); * settings.setValue("Support", true); * settings.setValue("Help/Language", "en_UK"); * * Properties properties * properties.load(&settings) * * // properties (("Package", "Full"), ("Background", ""), ("Support", "true")) * \endcode */ void load(const QSettings &rSettings); QStringList propertyNames() const; // JAVA: void save(QIODevice *pDevice) const; private: void parseProperty(const QString &rProperty, int line); static int hexDigitValue(const QChar &rDigit); static QString trimLeft(const QString &rString); private: Properties *mpDefaultProperties; static const char msEscapeChar; static const char *msValueEscapeCodes; static const char *msValueEscapeChars; static const char *msKeyEscapeCodes; static const char *msKeyEscapeChars; }; /************************************************************************** * Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM /*! * \relates Properties * * Writes all object member variables to the given debug stream \a rDebug and * returns the stream. * * * %Properties(default:0x0 properties:QHash(("log4j.appender.testAppender.layout", "org.apache.log4j.PatternLayout ") * ("log4j.appender.testAppender.layout.ConversionPattern", "[%t] %-5p %l: %m%n") * ("log4j.appender.testAppender.Append", "false ") * ("log4j.appender.testAppender.File", "output/temp ") * ("log4j.rootCategory", "TRACE, testAppender") * ("log4j.appender.testAppender", "org.apache.log4j.FileAppender")) ) * * \sa QDebug */ QDebug operator<<(QDebug debug, const Properties &rProperties); #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Inline **************************************************************************/ inline Properties::Properties(Properties *pDefaultProperties) : mpDefaultProperties(pDefaultProperties) {} inline Properties *Properties::defaultProperties() const { return mpDefaultProperties; } inline void Properties::setDefaultProperties(Properties *pDefaultProperties) { mpDefaultProperties = pDefaultProperties; } inline void Properties::setProperty(const QString &rKey, const QString &rValue) { insert(rKey, rValue); } } // namespace Log4Qt Q_DECLARE_TYPEINFO(Log4Qt::Properties, Q_MOVABLE_TYPE); #endif // LOG4QT_PROPERTIES_H ukui-interface/src/log4qt/log4qt/helpers/configuratorhelper.cpp0000664000175000017500000000744515167726064023726 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: configuratorhelper.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/helpers/configuratorhelper.h" #include #include #include "log4qt/helpers/initialisationhelper.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: ConfiguratorHelper **************************************************************************/ ConfiguratorHelper::ConfiguratorHelper() : mObjectGuard(), mConfigurationFile(), mpConfigureFunc(0), mpConfigurationFileWatch(0), mConfigureError() { } ConfiguratorHelper::~ConfiguratorHelper() { delete mpConfigurationFileWatch; } LOG4QT_IMPLEMENT_INSTANCE(ConfiguratorHelper) void ConfiguratorHelper::doConfigurationFileChanged(const QString &rFileName) { QMutexLocker locker(&mObjectGuard); if (!mpConfigureFunc) return; mpConfigureFunc(rFileName); // Shall we hold the lock while emitting the signal? emit configurationFileChanged(rFileName, mConfigureError.count() > 0); } void ConfiguratorHelper::doSetConfigurationFile(const QString &rFileName, ConfigureFunc pConfigureFunc) { QMutexLocker locker(&mObjectGuard); mConfigurationFile.clear(); mpConfigureFunc = 0; delete mpConfigurationFileWatch; if (rFileName.isEmpty()) return; mConfigurationFile = rFileName; mpConfigureFunc = pConfigureFunc; mpConfigurationFileWatch = new QFileSystemWatcher(); mpConfigurationFileWatch->addPath(rFileName); connect(mpConfigurationFileWatch, SIGNAL(fileChanged(const QString &)), SLOT(configurationFileChanged(const QString &))); } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const ConfiguratorHelper &rConfiguratorHelper) { debug.nospace() << "ConfiguratorHelper(" << "configurationfile:" << ConfiguratorHelper::configurationFile() << "configurefunc:" << rConfiguratorHelper.mpConfigureFunc << "filesystemwatcher:" << rConfiguratorHelper.mpConfigurationFileWatch << ")"; return debug.space(); } #endif // QT_NO_DEBUG_STREAM } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/helpers/patternformatter.h0000664000175000017500000001573415167726076023075 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: patternformatter.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_PATTERNFORMATTER_H #define LOG4QT_PATTERNFORMATTER_H #include "ukui-logmacros.h" /****************************************************************************** * Dependencies ******************************************************************************/ #include #include /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { class FormattingInfo; class PatternConverter; class LoggingEvent; /*! * \brief The class PatternFormatter formats a logging event based on a * pattern string. * * The class PatternFormatter formats a LoggingEvent base on a pattern * string. It is used by the patternLayout and TTCCLayout class to * implement the formatting. * * On object construction the provided patterns tring is parsed. Based on * the information found a chain of PatternConverter is created. Each * PatternConverter handles a certain member of a LoggingEvent. * * \sa PatternLayout::format() * \sa TTCCLayout::format() */ class LIBUKUILOG4QT_EXPORT PatternFormatter { public: /*! * Creates a PatternFormatter using a the specified \a rPattern. */ PatternFormatter(const QString &rPattern); /*! * Destroys the PatternFormatter and all PatternConverter. */ virtual ~PatternFormatter(); private: PatternFormatter(const PatternFormatter &rOther); // Not implemented PatternFormatter &operator=(const PatternFormatter &rOther); // Not implemented public: /*! * Formats the given \a rLoggingEvent using the chain of * PatternConverter created during construction from the specified * pattern. */ QString format(const LoggingEvent &rLoggingEvent) const; private: /*! * If the character \a rDigit is a digit the digit is added to the * integer \a rValue and the function returns true. Otherwise the * function returns false. * * The function adds the digit by multiplying the existing value * with ten and adding the numerical value of the digit. If the * maximum integer value would be exceeded by the operation * \a rValue is set to INT_MAX. */ bool addDigit(const QChar &rDigit, int &rValue); /*! * Creates a PatternConverter based on the specified conversion * character \a rChar, the formatting information * \a rFormattingInfo and the option \a rOption. * * The PatternConverter converter is appended to the list of * PatternConverters. */ void createConverter(const QChar &rChar, const FormattingInfo &rFormattingInfo, const QString &rOption = QString()); /*! * Creates a LiteralPatternConverter with the string literal * \a rLiteral. * * The PatternConverter converter is appended to the list of * PatternConverters. */ void createLiteralConverter(const QString &rLiteral); /*! * Parses the pattern string specified on construction and creates * PatternConverter according to it. */ void parse(); /*! * Parses an integer option from an option string. If the string is * not a valid integer or the integer value is less then zero, zero * is returned. Returns the end of line seperator for the operating * system. */ int parseIntegerOption(const QString &rOption); private: const QString mIgnoreCharacters; const QString mConversionCharacters; const QString mOptionCharacters; QString mPattern; QList mPatternConverters; // Needs to be friend to access internal data friend QDebug operator<<(QDebug, const PatternFormatter &rPatternFormatter); }; /************************************************************************** * Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM /*! * \relates PatternFormatter * * Writes all object member variables to the given debug stream \a rDebug and * returns the stream. * * * %PatternFormatter(pattern:"%r [%t] %p %c %x - %m%n" * converters:( * DatePatternConverter(FormattingInfo(min:"0" max:"INT_MAX" left:false) format: "TIME_RELATIVE" ) , * LiteralPatternConverter(FormattingInfo(min:"0" max:"INT_MAX" left:false) literal: " [" ) , * BasicPatternConverter(FormattingInfo(min:"0" max:"INT_MAX" left:false) type: "THREAD_CONVERTER" ) , * LiteralPatternConverter(FormattingInfo(min:"0" max:"INT_MAX" left:false) literal: "] " ) , * BasicPatternConverter(FormattingInfo(min:"0" max:"INT_MAX" left:false) type: "LEVEL_CONVERTER" ) , * LiteralPatternConverter(FormattingInfo(min:"0" max:"INT_MAX" left:false) literal: " " ) , * LoggerPatternConverter(FormattingInfo(min:"0" max:"INT_MAX" left:false) precision: 0 ) , * LiteralPatternConverter(FormattingInfo(min:"0" max:"INT_MAX" left:false) literal: " " ) , * BasicPatternConverter(FormattingInfo(min:"0" max:"INT_MAX" left:false) type: "NDC_CONVERTER" ) , * LiteralPatternConverter(FormattingInfo(min:"0" max:"INT_MAX" left:false) literal: " - " ) , * BasicPatternConverter(FormattingInfo(min:"0" max:"INT_MAX" left:false) type: "MESSAGE_CONVERTER" ) , * LiteralPatternConverter(FormattingInfo(min:"0" max:"INT_MAX" left:false) literal: "" ) ) ) * * \sa QDebug */ QDebug operator<<(QDebug debug, const PatternFormatter &rPatternFormatter); #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Inline **************************************************************************/ } // namespace Log4Qt #if QT_VERSION < 0x060000 Q_DECLARE_TYPEINFO(Log4Qt::PatternFormatter, Q_MOVABLE_TYPE); #else Q_DECLARE_TYPEINFO(Log4Qt::PatternFormatter, Q_COMPLEX_TYPE); #endif #endif // LOG4QT_PATTERNFORMATTER_H ukui-interface/src/log4qt/log4qt/helpers/configuratorhelper.h0000664000175000017500000001564415167726064023373 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: configuratorhelper.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_HELPERS_CONFIGURATORHELPER_H #define LOG4QT_HELPERS_CONFIGURATORHELPER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include #include #include #include "log4qt/loggingevent.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ class QFileSystemWatcher; namespace Log4Qt { /*! * \brief The class ConfiguratorHelper provides a confiuration file watch * and last error for configurator classes. * * A configuration file can be set using setConfigurationFile(). The file * is watched for changes. If a change occurs the configuration is reloaded * and the ConfigurationFileChanged() signal is emitted. Error information * for the last call to a configure function or the last configuration file * change can be accessed using configureError(). * * \note All the functions declared in this class are thread-safe. */ class LIBUKUILOG4QT_EXPORT ConfiguratorHelper : public QObject { Q_OBJECT public: /*! * Prototype for a configure callback function. The function is called * when then configuration file is changed and takes the * configuration file as a parameter. * * \sa setConfigurationFile(), * PropertyConfigurator::configure(const QString &) */ typedef bool (*ConfigureFunc)(const QString &rFileName); private: ConfiguratorHelper(); ConfiguratorHelper(const ConfiguratorHelper &rOther); // Not implemented virtual ~ConfiguratorHelper(); ConfiguratorHelper &operator=(const ConfiguratorHelper &rOther); // Not implemented public: /*! * Returns the error information for the last configuration operation * that took place. The configuration operation could be the result of * a call to one of the configure methods or through a change * to the configuration file. * * \sa setConfigureError(), PropertyConfigurator::configure(), * setConfigurationFile() */ static QList configureError(); /*! * Returns the current configuration file. * * \sa setConfigurationFile() */ static QString configurationFile(); /*! * Returns the ConfiguratorHelper instance. */ static ConfiguratorHelper *instance(); /*! * Sets the configuration error information for the last configuration * operation. * * \sa configureError() */ static void setConfigureError(const QList &rConfigureError); /*! * Sets the configuration file to \a rFileName. The file is watched for * changes. On a file change the function \a pConfigureFunc will be called * and the signal configurationFileChange() will be emitted. * * Setting the configuration file to an empty string stops the file watch. * * \sa configurationFile(), PropertyConfigurator::configureAndWatch(), * configureError() */ static void setConfigurationFile(const QString &rFileName = QString(), ConfigureFunc pConfigureFunc = 0); signals: /*! * The signal is emitted after a change to the file \a rFileName * was processed. If an error occured during the configuration, the * flag \a error will be true and error information is available * over configureError(). */ void configurationFileChanged(const QString &rFileName, bool error); private slots: void doConfigurationFileChanged(const QString &rFileName); private: void doSetConfigurationFile(const QString &rFileName, ConfigureFunc pConfigureFunc); private: mutable QMutex mObjectGuard; QString mConfigurationFile; ConfigureFunc mpConfigureFunc; QFileSystemWatcher *mpConfigurationFileWatch; QList mConfigureError; #ifndef QT_NO_DEBUG_STREAM // Needs to be friend to access details friend QDebug operator<<(QDebug debug, const ConfiguratorHelper &rConfiguratorHelper); #endif // QT_NO_DEBUG_STREAM }; /************************************************************************** * Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM /*! * \relates ConfiguratorHelper * * Writes all object member variables to the given debug stream \a rDebug and * returns the stream. * * * %ConfiguratorHelper(configurationfile: "" configurefunc: false * filesystemwatcher: QObject(0x0) ) * * \sa QDebug, ConfiguratorHelper::logManager() */ QDebug operator<<(QDebug debug, const ConfiguratorHelper &rConfiguratorHelper); #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Inline **************************************************************************/ inline QList ConfiguratorHelper::configureError() { QMutexLocker locker(&instance()->mObjectGuard); return instance()->mConfigureError; } inline QString ConfiguratorHelper::configurationFile() { QMutexLocker locker(&instance()->mObjectGuard); return instance()->mConfigurationFile; } inline void ConfiguratorHelper::setConfigureError(const QList &rConfigureError) { QMutexLocker locker(&instance()->mObjectGuard); instance()->mConfigureError = rConfigureError; } inline void ConfiguratorHelper::setConfigurationFile(const QString &rFileName, ConfigureFunc pConfigureFunc) { instance()->doSetConfigurationFile(rFileName, pConfigureFunc); } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::ConfiguratorHelper, Q_COMPLEX_TYPE); // use default #endif // LOG4QT_HELPERS_CONFIGURATORHELPER_H ukui-interface/src/log4qt/log4qt/helpers/properties.cpp0000664000175000017500000002401215167726064022205 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: properties.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/helpers/properties.h" #include #include #include #include #include "log4qt/logger.h" namespace Log4Qt { /************************************************************************** *Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ LOG4QT_DECLARE_STATIC_LOGGER(logger, Log4Qt::Properties) /************************************************************************** * Class implementation: Properties **************************************************************************/ void Properties::load(QIODevice *pDevice) { const QLatin1Char append_char(msEscapeChar); if (!pDevice) { logger()->warn("No device specified for load."); return; } QTextStream stream(pDevice); QString line; int line_number = 0; QString property; int property_start_line = 1; do { line = trimLeft(stream.readLine()); line_number++; if (!line.isEmpty() && line.at(line.length() - 1) == append_char) property += line.left(line.length() - 1); else { property += line; parseProperty(property, property_start_line); property.clear(); property_start_line = line_number + 1; } } while (!line.isNull()); } void Properties::load(const QSettings &rSettings) { QStringList keys = rSettings.childKeys(); QString key; Q_FOREACH(key, keys) insert(key, rSettings.value(key).toString()); } QString Properties::property(const QString &rKey) const { // Null string indicates the property does not contain the key. if (contains(rKey)) { QString value = this->value(rKey); if (value.isNull()) return QString(QLatin1String("")); else return value; } if (mpDefaultProperties) return mpDefaultProperties->property(rKey); else return QString(); } QString Properties::property(const QString &rKey, const QString &rDefaultValue) const { QString value = property(rKey); if (value.isNull()) return rDefaultValue; else return value; } QStringList Properties::propertyNames() const { QStringList default_keys; if (mpDefaultProperties) default_keys = mpDefaultProperties->propertyNames(); QStringList keys = this->keys(); QString key; Q_FOREACH(key, default_keys) if (!keys.contains(key)) keys << key; return keys; } void Properties::parseProperty(const QString &rProperty, int line) { Q_ASSERT_X(rProperty == trimLeft(rProperty), "parseProperty()", "rProperty has leading spaces"); enum State { KEY_STATE, KEYSPACE_STATE, SPACEVALUE_STATE, VALUE_STATE, KEYESCAPE_STATE, VALUEESCAPE_STATE, UNICODEESCAPE_STATE }; const QString value_escape_codes =QLatin1String(msValueEscapeCodes); const QString value_escape_chars = QLatin1String(msValueEscapeChars); Q_ASSERT_X(value_escape_codes.length() == value_escape_chars.length(), "parseProperty()", "Value escape sequence character definition does not map"); const QString key_escape_codes = QLatin1String(msKeyEscapeCodes); const QString key_escape_chars = QLatin1String(msKeyEscapeChars); Q_ASSERT_X(key_escape_codes.length() == key_escape_chars.length(), "parseProperty()", "Key escape sequence character definition does not map"); if (rProperty.isEmpty()) return; int i = 0; QChar c; char ch; State state = KEY_STATE; QString key; QString value; QString *p_string = &key; uint ucs; int ucs_digits; while (i < rProperty.length()) { // i points to the current character. // c contains the current character // ch contains the Latin1 equivalent of the current character // i is incremented at the end of the loop to consume the character. // continue is used to change state without consuming the character c = rProperty.at(i); ch = c.toLatin1(); switch (state) { case KEY_STATE: if (ch == '!' || ch == '#' ) return; else if (c.isSpace()) { p_string = &value; state = KEYSPACE_STATE; } else if (ch == '=' || ch == ':') { p_string = &value; state = SPACEVALUE_STATE; } else if (ch == msEscapeChar) state = KEYESCAPE_STATE; else *p_string += c; break; case KEYSPACE_STATE: if (ch == '=' || ch == ':') state = SPACEVALUE_STATE; else if (!c.isSpace()) { *p_string += c; state = VALUE_STATE; } break; case SPACEVALUE_STATE: if (!c.isSpace()) { *p_string += c; state = VALUE_STATE; } break; case VALUE_STATE: if (ch == msEscapeChar) state = VALUEESCAPE_STATE; else *p_string += c; break; case KEYESCAPE_STATE: { int convert = key_escape_codes.indexOf(c); if (convert >= 0) *p_string += key_escape_chars.at(convert); else { logger()->warn("Unknown escape sequence '\\%1' in key of property starting at line %2", QString(c), line); *p_string += c; } state = KEY_STATE; break; } case VALUEESCAPE_STATE: { int convert = value_escape_codes.indexOf(c); if (convert >= 0) { *p_string += value_escape_chars.at(convert); state = VALUE_STATE; } else if (ch == 'u') { ucs = 0; ucs_digits = 0; state = UNICODEESCAPE_STATE; } else { logger()->warn("Unknown escape sequence '\\%1' in value of property starting at line %2", QString(c), line); *p_string += c; state = VALUE_STATE; } break; } case UNICODEESCAPE_STATE: { int hex = hexDigitValue(c); if (hex >= 0) { ucs = ucs * 16 + hex; ucs_digits++; if (ucs_digits == 4 || i == rProperty.length() - 1) { *p_string += QChar(ucs); state = VALUE_STATE; } } else { if (ucs_digits > 0) *p_string += QChar(ucs); state = VALUE_STATE; continue; } break; } default: Q_ASSERT_X(false, "Properties::parseProperty()", "Unknown state constant"); return; } i++; } if (key.isEmpty() && !value.isEmpty()) logger()->warn("Found value with no key in property starting at line %1", line); logger()->trace("Loaded property '%1' : '%2'", key, value); insert(key, value); } int Properties::hexDigitValue(const QChar &rDigit) { bool ok; int result = QString(rDigit).toInt(&ok, 16); if (!ok) return -1; else return result; } QString Properties::trimLeft(const QString &rLine) { int i = 0; while (i < rLine.length() && rLine.at(i).isSpace()) i++; return rLine.right(rLine.length() - i); } const char Properties::msEscapeChar ='\\'; const char *Properties::msValueEscapeCodes = "tnr\\\"\' "; const char *Properties::msValueEscapeChars = "\t\n\r\\\"\' "; const char *Properties::msKeyEscapeCodes = " :="; const char *Properties::msKeyEscapeChars = " :="; /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const Properties &rProperties) { debug.nospace() << "Properties(" << "default:" << rProperties.defaultProperties() << " " << "properties:" << *reinterpret_cast *>(&rProperties) << ")"; return debug.space(); } #endif } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/helpers/classlogger.cpp0000664000175000017500000000641315167726076022326 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: classlogger.cpp * created: September 2007 * author: Martin Heinrich * * * changes: Sep 2008, Martin Heinrich: * - Replaced usage of q_atomic_test_and_set_ptr with * QAtomicPointer * * * Copyright 2007 - 2008 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/helpers/classlogger.h" #include #include "log4qt/logmanager.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: ClassLogger **************************************************************************/ ClassLogger::ClassLogger() : mpLogger(0) { } Logger *ClassLogger::logger(const QObject *pObject) { Q_ASSERT_X(pObject, "ClassLogger::logger()", "pObject must not be null"); #if QT_VERSION < 0x040400 if (!mpLogger) q_atomic_test_and_set_ptr(&mpLogger, 0, LogManager::logger(QLatin1String(pObject->metaObject()->className()))); return const_cast(mpLogger); #elif QT_VERSION < 0x050000 if (!static_cast(mpLogger)) mpLogger.testAndSetOrdered(0, LogManager::logger(QLatin1String(pObject->metaObject()->className()))); return const_cast(static_cast(mpLogger)); #elif QT_VERSION < 0x060000 if (!static_cast(mpLogger.loadAcquire())) mpLogger.testAndSetOrdered(0, LogManager::logger(QLatin1String(pObject->metaObject()->className()))); return const_cast(static_cast(mpLogger.loadAcquire())); #else Logger* expected = nullptr; Logger* desired = LogManager::logger(QLatin1String(pObject->metaObject()->className())); mpLogger.compare_exchange_weak(expected, desired); return mpLogger.load(); #endif } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/helpers/asyncdispatcher.h0000664000175000017500000000300315167726064022637 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see #include "ukui-logmacros.h" namespace Log4Qt { class AppenderSkeleton; /*! * \brief The class AsyncDispatcher does the actual logging to the attached appanders. * * The Dispatcher is the worker object which class the attached apperders in the * the context of the AsyncDispatcherThread. * * \note All the functions declared in this class are thread-safe. */ class LIBUKUILOG4QT_EXPORT AsyncDispatcher : public QObject { Q_OBJECT public: explicit AsyncDispatcher(QObject *parent = nullptr); void setAsyncAppender(AppenderSkeleton *asyncAppender); protected: void customEvent(QEvent *event) override; private: AppenderSkeleton *mAsyncAppender; }; } // namespace Log4Qt #endif // LOG4QT_ASYNCDISPATCHER_H ukui-interface/src/log4qt/log4qt/helpers/initialisationhelper.cpp0000664000175000017500000001274615167726076024247 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: initialisationhelper.cpp * created: September 2007 * author: Martin Heinrich * * * changes Feb 2009, Martin Heinrich * - Fixed VS 2008 unreferenced formal parameter warning by using * Q_UNUSED in operator<<. * * * Copyright 2007 - 2009 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/helpers/initialisationhelper.h" #include #include #include #include #include #ifndef QT_NO_DATASTREAM #include #endif #include "log4qt/helpers/datetime.h" #include "log4qt/helpers/logerror.h" #include "log4qt/loggingevent.h" namespace Log4Qt { /************************************************************************** *Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: InitialisationHelper **************************************************************************/ InitialisationHelper::InitialisationHelper() : mStartTime(DateTime::currentDateTime().toMilliSeconds()), mEnvironmentSettings() { doRegisterTypes(); doInitialiseEnvironmentSettings(); } InitialisationHelper::~InitialisationHelper() { Q_ASSERT_X(false, "InitialisationHelper::~InitialisationHelper()", "Unexpected destruction of singleton object"); } LOG4QT_IMPLEMENT_INSTANCE(InitialisationHelper) void InitialisationHelper::doInitialiseEnvironmentSettings() { // Is Process::systemEnvironment() safe to be used before a QCoreApplication // object has been created? QStringList setting_keys; setting_keys << QLatin1String("Debug"); setting_keys << QLatin1String("DefaultInitOverride"); setting_keys << QLatin1String("Configuration"); setting_keys << QLatin1String("ConfiguratorClass"); QHash env_keys; QString entry; Q_FOREACH(entry, setting_keys) env_keys.insert(QString::fromLatin1("log4qt_").append(entry).toUpper(), entry); QStringList sys_env = QProcess::systemEnvironment(); Q_FOREACH(entry, sys_env) { int i = entry.indexOf(QLatin1Char('=')); if (i == -1) continue; QString key = entry.left(i); QString value = entry.mid(i + 1).trimmed(); if (env_keys.contains(key)) mEnvironmentSettings.insert(env_keys.value(key), value); } } void InitialisationHelper::doRegisterTypes() { qRegisterMetaType("Log4Qt::LogError"); qRegisterMetaType("Log4Qt::Level"); qRegisterMetaType("Log4Qt::LoggingEvent"); #ifndef QT_NO_DATASTREAM #if QT_VERSION < 0x060000 qRegisterMetaTypeStreamOperators("Log4Qt::LogError"); qRegisterMetaTypeStreamOperators("Log4Qt::Level"); qRegisterMetaTypeStreamOperators("Log4Qt::LoggingEvent"); #endif #endif } QString InitialisationHelper::doSetting(const QString &rKey, const QString &rDefault) const { if (mEnvironmentSettings.contains(rKey)) return mEnvironmentSettings.value(rKey); if (QCoreApplication::instance()) { QSettings s; s.beginGroup(QLatin1String("Log4Qt")); return s.value(rKey, rDefault).toString().trimmed(); } else return rDefault; } bool InitialisationHelper::staticInitialisation() { instance(); return true; } bool InitialisationHelper::msStaticInitialisation = staticInitialisation(); /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const InitialisationHelper &rInitialisationHelper) { Q_UNUSED(rInitialisationHelper); debug.nospace() << "InitialisationHelper(" << "starttime:" << InitialisationHelper::startTime() << "(" << DateTime::fromMilliSeconds(InitialisationHelper::startTime()) << ")" << "environmentsettings:" << InitialisationHelper::environmentSettings() << ")"; return debug.space(); } #endif // QT_NO_DEBUG_STREAM } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/helpers/logobject.h0000664000175000017500000001442215167726076021435 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: logobject.h * created: September 2007 * author: Martin Heinrich * * * changes: Sep 2008, Martin Heinrich: * - Replaced usage of q_atomic_increment and q_atomic_decrement * with QAtomicInt. * Feb 2009, Martin Heinrich * - Fixed a problem where the pParent parameter of the constructor * was not passed on to the QObject constructor * * * Copyright 2007 - 2009 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_LOGOBJECT_H #define LOG4QT_LOGOBJECT_H #include "ukui-logmacros.h" /****************************************************************************** * Dependencies ******************************************************************************/ #include #include "log4qt/helpers/classlogger.h" #if QT_VERSION >= 0x040400 && QT_VERSION < 0x060000 # include # ifndef Q_ATOMIC_INT_REFERENCE_COUNTING_IS_ALWAYS_NATIVE # warning "QAtomicInt reference counting is not native. The class Log4Qt::LogObject is not thread-safe." # endif #elif QT_VERSION >= 0x060000 # include #endif namespace Log4Qt { class Logger; /*! * \brief The class LogObject is the common base class for many classes * in the package. * * The class inherits QObject to allow its subclass to be accessed using * the Qt property system. * * LogObject objects provide a reference counter. A reference to the * object is established by calling retain() and freed by calling * release(). The object will delete itself when the reference counter * is decremented to 0. * * A class specific logger can be accessed over logger(). * * The class also implements generic streaming to QDebug. Streaming an * object to QDebug will invoke debug() to create class specific output. * * \note All the functions declared in this class are thread-safe. * * \sa \ref Ownership "Object ownership", * LOG4QT_DECLARE_QCLASS_LOGGER */ class LIBUKUILOG4QT_EXPORT LogObject : public QObject { Q_OBJECT public: /*! * Creates a LogObject which is a child of \a pObject. */ LogObject(QObject *pObject = 0); /*! * Destroys the LogObject. */ virtual ~LogObject(); private: LogObject(const LogObject &rOther); // Not implemented LogObject &operator=(const LogObject &rOther); // Not implemented public: /*! * Returns the value of the reference counter. */ int referenceCount() const; /*! * Decrements the reference count of the object. If the reference count * count reaches zero and the object does not have a parent the object * is deleted. */ void release(); /*! * Increments the reference count of the object. */ void retain(); protected: #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream * \a rDebug and returns the stream. * * The member function is used by * QDebug operator<<(QDebug debug, const LogObject &rLogObject) to * generate class specific output. * * \sa QDebug operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const = 0; // Needs to be friend to access internal data friend QDebug operator<<(QDebug debug, const LogObject &rLogObject); #endif // QT_NO_DEBUG_STREAM /*! * Returns a pointer to a Logger named after of the object. * * \sa Logger::logger(const char *pName) */ Logger* logger() const; private: #if QT_VERSION < 0x040400 volatile int mReferenceCount; #elif QT_VERSION < 0x060000 mutable QAtomicInt mReferenceCount; #else mutable std::atomic mReferenceCount; #endif mutable ClassLogger mLog4QtClassLogger; }; /************************************************************************** * Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM /*! * \relates LogObject * * Writes all object member variables to the given debug stream \a debug * and returns the stream. * * To handle sub-classing the function uses the virtual member function * debug(). This allows each class to generate its own output. * * \sa QDebug, debug() */ QDebug operator<<(QDebug debug, const LogObject &rLogObject); #endif /************************************************************************** * Inline **************************************************************************/ inline LogObject::LogObject(QObject *pParent) : QObject(pParent), mReferenceCount() {} inline LogObject::~LogObject() {} inline int LogObject::referenceCount() const #if QT_VERSION < 0x050000 { return mReferenceCount; } #elif QT_VERSION < 0x060000 { return mReferenceCount.loadAcquire(); } #else { return mReferenceCount.load(); } #endif inline void LogObject::release() #if QT_VERSION < 0x040400 { if ((q_atomic_decrement(&mReferenceCount) == 0) && !parent()) delete(this); } #elif QT_VERSION < 0x060000 { if (!mReferenceCount.deref()) delete(this); } #else { if (mReferenceCount.fetch_sub(1) == 1) delete(this); } #endif inline void LogObject::retain() #if QT_VERSION < 0x040400 { q_atomic_increment(&mReferenceCount); } #elif QT_VERSION < 0x060000 { mReferenceCount.ref(); } #else { mReferenceCount.fetch_add(1); } #endif inline Logger *LogObject::logger() const { return mLog4QtClassLogger.logger(this); } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::LogObject, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_LOGOBJECT_H ukui-interface/src/log4qt/log4qt/helpers/optionconverter.cpp0000664000175000017500000002373615167726076023270 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: optionconverter.cpp * created: September 2007 * author: Martin Heinrich * * * changes Feb 2009, Martin Heinrich * - Fixed a problem were OptionConverter::toBoolean would not * return the default value, if the conversion fails. * * * Copyright 2007 - 2009 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/helpers/optionconverter.h" #include #include "log4qt/helpers/logerror.h" #include "log4qt/helpers/properties.h" #include "log4qt/logger.h" #include "log4qt/consoleappender.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ LOG4QT_DECLARE_STATIC_LOGGER(logger, Log4Qt::OptionConverter) /************************************************************************** * Class implementation: OptionConverter **************************************************************************/ QString OptionConverter::findAndSubst(const Properties &rProperties, const QString &rKey) { QString value = rProperties.property(rKey); if (value.isNull()) return value; const QString begin_subst = QLatin1String("${"); const QString end_subst = QLatin1String("}"); const int begin_length = begin_subst.length(); const int end_length = end_subst.length(); // Don't return a null string, the null string indicates that the // property key does not exist. QString result = QLatin1String(""); int i = 0; int begin; int end; while (i < value.length()) { begin = value.indexOf(begin_subst, i); if (begin == -1) { result += value.mid(i); i = value.length(); } else { result += value.mid(i, begin - i); end = value.indexOf(end_subst, i + begin_length); if (end == -1) { LogError e = LOG4QT_ERROR(QT_TR_NOOP("Missing closing bracket for opening bracket at %1. Invalid substitution in value %2."), CONFIGURATOR_INVALID_SUBSTITUTION_ERROR, "Log4Qt::OptionConverter"); e << begin << value; logger()->error(e); return result; } else { result += findAndSubst(rProperties, value.mid(begin + begin_length, end - begin - end_length - 1)); i = end + end_length; } } } return result; } QString OptionConverter::classNameJavaToCpp(const QString &rClassName) { const QLatin1String java_class_delimiter("."); const QLatin1String cpp_class_delimiter("::"); QString result = rClassName; return result.replace(java_class_delimiter, cpp_class_delimiter); } bool OptionConverter::toBoolean(const QString &rOption, bool *p_ok) { const QLatin1String str_true("true"); const QLatin1String str_enabled("enabled"); const QLatin1String str_one("1"); const QLatin1String str_false("false"); const QLatin1String str_disabled("disabled"); const QLatin1String str_zero("0"); if (p_ok) *p_ok = true; QString s = rOption.trimmed().toLower(); if (s == str_true || s == str_enabled || s == str_one) return true; if (s == str_false || s == str_disabled || s == str_zero) return false; if (p_ok) *p_ok = false; LogError e = LOG4QT_ERROR(QT_TR_NOOP("Invalid option string '%1' for a boolean"), CONFIGURATOR_INVALID_OPTION_ERROR, "Log4Qt::OptionConverter"); e << rOption; logger()->error(e); return false; } bool OptionConverter::toBoolean(const QString &rOption, bool default_value) { bool ok; bool result = toBoolean(rOption, &ok); if (ok) return result; else return default_value; } qint64 OptionConverter::toFileSize(const QString &rOption, bool *p_ok) { // - Search for unit // - Convert characters befor unit to int // - Error, if // - the conversion failed // - the value < 0 // - there is text after the unit characters if (p_ok) *p_ok = false; QString s = rOption.trimmed().toLower(); qint64 f = 1; int i; i = s.indexOf(QLatin1String("kb")); if (i >= 0) f = 1024; else { i = s.indexOf(QLatin1String("mb")); if (i >= 0) f = 1024 * 1024; else { i = s.indexOf(QLatin1String("gb")); if (i >= 0) f = 1024 * 1024 * 1024; } } if (i < 0) i = s.length(); bool ok; qint64 value = s.left(i).toLongLong(&ok); if (!ok || value < 0 || s.length() > i + 2) { LogError e = LOG4QT_ERROR(QT_TR_NOOP("Invalid option string '%1' for a file size"), CONFIGURATOR_INVALID_OPTION_ERROR, "Log4Qt::OptionConverter"); e << rOption; logger()->error(e); return 0; } if (p_ok) *p_ok = true; return value * f; } int OptionConverter::toInt(const QString &rOption, bool *p_ok) { int value = rOption.trimmed().toInt(p_ok); if (*p_ok) return value; LogError e = LOG4QT_ERROR(QT_TR_NOOP("Invalid option string '%1' for an integer"), CONFIGURATOR_INVALID_OPTION_ERROR, "Log4Qt::OptionConverter"); e << rOption; logger()->error(e); return 0; } qint64 OptionConverter::toQInt64(const QString &rOption, bool *p_ok) { int value = rOption.trimmed().toLongLong(p_ok); if (*p_ok) return value; LogError e = LOG4QT_ERROR(QT_TR_NOOP("Invalid option string '%1' for an qint64"), CONFIGURATOR_INVALID_OPTION_ERROR, "Log4Qt::OptionConverter"); e << rOption; logger()->error(e); return 0; } Level OptionConverter::toLevel(const QString &rOption, bool *p_ok) { bool ok; Level level = Level::fromString(rOption.toUpper().trimmed(), &ok); if (p_ok) *p_ok = ok; if (ok) return Level(level); LogError e = LOG4QT_ERROR(QT_TR_NOOP("Invalid option string '%1' for a level"), CONFIGURATOR_INVALID_OPTION_ERROR, "Log4Qt::OptionConverter"); e << rOption; logger()->error(e); return Level(level); } Level OptionConverter::toLevel(const QString &rOption, const Level &rDefaultValue) { bool ok; Level result = toLevel(rOption, &ok); if (ok) return Level(result); else return rDefaultValue; } int OptionConverter::toTarget(const QString &rOption, bool *p_ok) { const QLatin1String java_stdout("system.out"); const QLatin1String cpp_stdout("stdout_target"); const QLatin1String java_stderr("system.err"); const QLatin1String cpp_stderr("stderr_target"); if (p_ok) *p_ok = true; QString s = rOption.trimmed().toLower(); if (s == java_stdout || s == cpp_stdout) return ConsoleAppender::STDOUT_TARGET; if (s == java_stderr || s == cpp_stderr) return ConsoleAppender::STDERR_TARGET; if (p_ok) *p_ok = false; LogError e = LOG4QT_ERROR(QT_TR_NOOP("Invalid option string '%1' for a target"), CONFIGURATOR_INVALID_OPTION_ERROR, "Log4Qt::OptionConverter"); e << rOption; logger()->error(e); return ConsoleAppender::STDOUT_TARGET; } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/helpers/patternformatter.cpp0000664000175000017500000006277315167726064023432 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: patternformatter.cpp * created: September 2007 * author: Martin Heinrich * * * changes Feb 2009, Martin Heinrich * - Fixed VS 2008 unreferenced formal parameter warning by using * Q_UNUSED in LiteralPatternConverter::convert. * * * Copyright 2007 - 2009 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/helpers/patternformatter.h" #include #include #include #include "log4qt/helpers/datetime.h" #include "log4qt/helpers/logerror.h" #include "log4qt/layout.h" #include "log4qt/logger.h" #include "log4qt/loggingevent.h" namespace Log4Qt { /************************************************************************** *Declarations **************************************************************************/ /*! * \brief The class FormattingInfo stores the formatting modifier for a * pattern converter. * * \sa PatternConverter */ class FormattingInfo { public: FormattingInfo() { clear(); } // FormattingInfo(const FormattingInfo &rOther); // Use compiler default // virtual ~FormattingInfo(); // Use compiler default // FormattingInfo &operator=(const FormattingInfo &rOther); // Use compiler default void clear(); static QString intToString(int i); public: int mMinLength; int mMaxLength; bool mLeftAligned; }; /*! * \brief The class PatternConverter is the abstract base class for all * pattern converters. * * PatternConverter handles the minimum and maximum modifier for a * conversion character. The actual conversion is by calling the * convert() member function of the derived class. * * \sa PatternLayout::format() */ class PatternConverter { public: PatternConverter(const FormattingInfo &rFormattingInfo = FormattingInfo()) : mFormattingInfo(rFormattingInfo) {}; virtual ~PatternConverter() {}; private: PatternConverter(const PatternConverter &rOther); // Not implemented PatternConverter &operator=(const PatternConverter &rOther); // Not implemented public: void format(QString &rFormat, const LoggingEvent &rLoggingEvent) const; protected: virtual QString convert(const LoggingEvent &rLoggingEvent) const = 0; #ifndef QT_NO_DEBUG_STREAM virtual QDebug debug(QDebug &rDebug) const = 0; friend QDebug operator<<(QDebug, const PatternConverter &rPatternConverter); #endif protected: FormattingInfo mFormattingInfo; }; /*! * \brief The class BasicPatternConverter converts several members of a * LoggingEvent to a string. * * BasicPatternConverter is used by PatternLayout to convert members that * do not reuquire additional formatting to a string as part of formatting * the LoggingEvent. It handles the following conversion characters: * 'm', 'p', 't', 'x' * * \sa PatternLayout::format() * \sa PatternConverter::format() */ class BasicPatternConverter : public PatternConverter { public: enum Type { MESSAGE_CONVERTER, NDC_CONVERTER, LEVEL_CONVERTER, THREAD_CONVERTER, }; public: BasicPatternConverter(const FormattingInfo &rFormattingInfo, Type type) : PatternConverter(rFormattingInfo), mType(type) {}; // virtual ~BasicPatternConverter(); // Use compiler default private: BasicPatternConverter(const BasicPatternConverter &rOther); // Not implemented BasicPatternConverter &operator=(const BasicPatternConverter &rOther); // Not implemented protected: virtual QString convert(const LoggingEvent &rLoggingEvent) const; #ifndef QT_NO_DEBUG_STREAM virtual QDebug debug(QDebug &rDebug) const; #endif private: Type mType; }; /*! * \brief The class DatePatternConverter converts the time stamp of a * LoggingEvent to a string. * * DatePatternConverter is used by PatternLayout to convert the time stamp * of a LoggingEvent to a string as part of formatting the LoggingEvent. * It handles the 'd' and 'r' conversion character. * * \sa PatternLayout::format() * \sa PatternConverter::format() */ class DatePatternConverter : public PatternConverter { public: DatePatternConverter(const FormattingInfo &rFormattingInfo, const QString &rFormat) : PatternConverter(rFormattingInfo), mFormat(rFormat) {}; // virtual ~DatePatternConverter(); // Use compiler default private: DatePatternConverter(const DatePatternConverter &rOther); // Not implemented DatePatternConverter &operator=(const DatePatternConverter &rOther); // Not implemented protected: virtual QString convert(const LoggingEvent &rLoggingEvent) const; #ifndef QT_NO_DEBUG_STREAM virtual QDebug debug(QDebug &rDebug) const; #endif private: QString mFormat; }; /*! * \brief The class LiteralPatternConverter provides string literals. * * LiteralPatternConverter is used by PatternLayout to embed string * literals as part of formatting the LoggingEvent. It handles string * literals and the 'n' conversion character. * * \sa PatternLayout::format() * \sa PatternConverter::format() */ class LiteralPatternConverter : public PatternConverter { public: LiteralPatternConverter(const QString &rLiteral) : PatternConverter(), mLiteral(rLiteral) {}; // virtual ~LiteralPatternConverter(); // Use compiler default private: LiteralPatternConverter(const LiteralPatternConverter &rOther); // Not implemented LiteralPatternConverter &operator=(const LiteralPatternConverter &rOther); // Not implemented protected: virtual QString convert(const LoggingEvent &rLoggingEvent) const; #ifndef QT_NO_DEBUG_STREAM virtual QDebug debug(QDebug &rDebug) const; #endif private: QString mLiteral; }; /*! * \brief The class LoggerPatternConverter converts the Logger name of a * LoggingEvent to a string. * * LoggerPatternConverter is used by PatternLayout to convert the Logger * name of a LoggingEvent to a string as part of formatting the * LoggingEvent. It handles the 'c' conversion character. * * \sa PatternLayout::format() * \sa PatternConverter::format() */ class LoggerPatternConverter : public PatternConverter { public: LoggerPatternConverter(const FormattingInfo &rFormattingInfo, int precision) : PatternConverter(rFormattingInfo), mPrecision(precision) {}; // virtual ~LoggerPatternConverter(); // Use compiler default private: LoggerPatternConverter(const LoggerPatternConverter &rOther); // Not implemented LoggerPatternConverter &operator=(const LoggerPatternConverter &rOther); // Not implemented protected: virtual QString convert(const LoggingEvent &rLoggingEvent) const; #ifndef QT_NO_DEBUG_STREAM virtual QDebug debug(QDebug &rDebug) const; #endif private: int mPrecision; }; /*! * \brief The class MDCPatternConverter converts the MDC data of a * LoggingEvent to a string. * * MDCPatternConverter is used by PatternLayout to convert the MDC data of * a LoggingEvent to a string as part of formatting the LoggingEvent. It * handles the 'X' conversion character. * * \sa PatternLayout::format() * \sa PatternConverter::format() */ class MDCPatternConverter : public PatternConverter { public: MDCPatternConverter(const FormattingInfo &rFormattingInfo, const QString &rKey) : PatternConverter(rFormattingInfo), mKey(rKey) {}; // virtual ~MDCPatternConverter(); // Use compiler default private: MDCPatternConverter(const MDCPatternConverter &rOther); // Not implemented MDCPatternConverter &operator=(const MDCPatternConverter &rOther); // Not implemented protected: virtual QString convert(const LoggingEvent &rLoggingEvent) const; #ifndef QT_NO_DEBUG_STREAM virtual QDebug debug(QDebug &rDebug) const; #endif private: QString mKey; }; #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug, const FormattingInfo &rFormattingInfo); #endif #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug, const PatternConverter &rPatternConverter); #endif /************************************************************************** * C helper functions **************************************************************************/ LOG4QT_DECLARE_STATIC_LOGGER(logger, Log4Qt::PatternFormatter) /************************************************************************** * Class implementation: PatternFormatter **************************************************************************/ PatternFormatter::PatternFormatter(const QString &rPattern) : mIgnoreCharacters(QLatin1String("CFlLM")), mConversionCharacters(QLatin1String("cdmprtxX")), mOptionCharacters(QLatin1String("cd")), mPattern(rPattern), mPatternConverters() { parse(); } PatternFormatter::~PatternFormatter() { PatternConverter *p_converter; Q_FOREACH(p_converter, mPatternConverters) delete p_converter; } QString PatternFormatter::format(const LoggingEvent &rLoggingEvent) const { QString result; PatternConverter *p_converter; Q_FOREACH(p_converter, mPatternConverters) p_converter->format(result, rLoggingEvent); return result; } bool PatternFormatter::addDigit(const QChar &rDigit, int &rValue) { if (!rDigit.isDigit()) return false; int digit_value = rDigit.digitValue(); if (rValue > (INT_MAX - digit_value) / 10) rValue = INT_MAX; else rValue = rValue * 10 + digit_value; return true; } void PatternFormatter::createConverter(const QChar &rChar, const FormattingInfo &rFormattingInfo, const QString &rOption) { Q_ASSERT_X(mConversionCharacters.indexOf(rChar) >= 0, "PatternFormatter::createConverter", "Unknown conversion character" ); LogError e("Creating Converter for character '%1' min %2, max %3, left %4 and option '%5'"); e << QString(rChar) << FormattingInfo::intToString(rFormattingInfo.mMinLength) << FormattingInfo::intToString(rFormattingInfo.mMaxLength) << rFormattingInfo.mLeftAligned << rOption; logger()->trace(e); switch (rChar.toLatin1()) { case 'c': mPatternConverters << new LoggerPatternConverter(rFormattingInfo, parseIntegerOption(rOption)); break; case 'd': { QString option = rOption; if (rOption.isEmpty()) option = QLatin1String("ISO8601"); mPatternConverters << new DatePatternConverter(rFormattingInfo, option); break; } case 'm': mPatternConverters << new BasicPatternConverter(rFormattingInfo, BasicPatternConverter::MESSAGE_CONVERTER); break; case 'p': mPatternConverters << new BasicPatternConverter(rFormattingInfo, BasicPatternConverter::LEVEL_CONVERTER); break; case 'r': mPatternConverters << new DatePatternConverter(rFormattingInfo, QLatin1String("TIME_RELATIVE")); break; case 't': mPatternConverters << new BasicPatternConverter(rFormattingInfo, BasicPatternConverter::THREAD_CONVERTER); break; case 'x': mPatternConverters << new BasicPatternConverter(rFormattingInfo, BasicPatternConverter::NDC_CONVERTER); break; case 'X': mPatternConverters << new MDCPatternConverter(rFormattingInfo, rOption); break; default: Q_ASSERT_X(false, "PatternFormatter::createConverter", "Unknown pattern character"); } } void PatternFormatter::createLiteralConverter(const QString &rLiteral) { logger()->trace("Creating literal LiteralConverter with Literal '%1'", rLiteral); mPatternConverters << new LiteralPatternConverter(rLiteral); } void PatternFormatter::parse() { enum State { LITERAL_STATE, ESCAPE_STATE, MIN_STATE, DOT_STATE, MAX_STATE, CHARACTER_STATE, POSSIBLEOPTION_STATE, OPTION_STATE }; int i = 0; QChar c; char ch; State state = LITERAL_STATE; FormattingInfo formatting_info; QString literal; int converter_start; int option_start; while (i < mPattern.length()) { // i points to the current character // c contains the current character // ch contains the Latin1 equivalent of the current character // i is incremented at the end of the loop to consume the character // continue is used to change state without consuming the character c = mPattern.at(i); ch = c.toLatin1(); switch (state) { case LITERAL_STATE: if (ch == '%') { formatting_info.clear(); converter_start = i; state = ESCAPE_STATE; } else literal += c; break; case ESCAPE_STATE: if (ch == '%') { literal += c; state = LITERAL_STATE; } else if (ch == 'n') { literal += Layout::endOfLine(); state = LITERAL_STATE; } else { if (!literal.isEmpty()) { createLiteralConverter(literal); literal.clear(); } if (ch == '-') formatting_info.mLeftAligned = true; else if (c.isDigit()) { formatting_info.mMinLength = c.digitValue(); state = MIN_STATE; } else if (ch == '.') state = DOT_STATE; else { state = CHARACTER_STATE; continue; } } break; case MIN_STATE: if (!addDigit(c, formatting_info.mMinLength)) { if (ch == '.') state = DOT_STATE; else { state = CHARACTER_STATE; continue; } } break; case DOT_STATE: if (c.isDigit()) { formatting_info.mMaxLength = c.digitValue(); state = MAX_STATE; } else { LogError e = LOG4QT_ERROR(QT_TR_NOOP("Found character '%1' where digit was expected."), LAYOUT_EXPECTED_DIGIT_ERROR, "Log4Qt::PatternFormatter"); e << QString(c); logger()->error(e); } break; case MAX_STATE: if (!addDigit(c, formatting_info.mMaxLength)) { state = CHARACTER_STATE; continue; } break; case CHARACTER_STATE: if (mIgnoreCharacters.indexOf(c) >= 0) state = LITERAL_STATE; else if (mOptionCharacters.indexOf(c) >= 0) state = POSSIBLEOPTION_STATE; else if (mConversionCharacters.indexOf(c) >= 0) { createConverter(c, formatting_info); state = LITERAL_STATE; } else { logger()->warn("Invalid conversion character '%1' at %2 in pattern '%3'", c, i, mPattern); createLiteralConverter(mPattern.mid(converter_start, i - converter_start + 1)); state = LITERAL_STATE; } break; case POSSIBLEOPTION_STATE: if (ch == '{') { option_start = i; state = OPTION_STATE; } else { createConverter(mPattern.at(i - 1), formatting_info); state = LITERAL_STATE; continue; } break; case OPTION_STATE: if (ch == '}') { createConverter(mPattern.at(option_start - 1), formatting_info, mPattern.mid(option_start + 1, i - option_start - 1)); state = LITERAL_STATE; } break; default: Q_ASSERT_X(false, "PatternFormatter::parse()", "Unknown parsing state constant"); state = LITERAL_STATE; } i++; } if (state != LITERAL_STATE) { logger()->warn("Unexptected end of pattern '%1'", mPattern); if (state == ESCAPE_STATE) literal += c; else literal += mPattern.mid(converter_start); } if (!literal.isEmpty()) createLiteralConverter(literal); } int PatternFormatter::parseIntegerOption(const QString &rOption) { if (rOption.isEmpty()) return 0; bool ok; int result = rOption.toInt(&ok); if (!ok) { LogError e = LOG4QT_ERROR(QT_TR_NOOP("Option '%1' cannot be converted into an integer"), LAYOUT_OPTION_IS_NOT_INTEGER_ERROR, "Log4Qt::PatterFormatter"); e << rOption; logger()->error(e); } if (result < 0) { LogError e = LOG4QT_ERROR(QT_TR_NOOP("Option %1 isn't a positive integer"), LAYOUT_INTEGER_IS_NOT_POSITIVE_ERROR, "Log4Qt::PatterFormatter"); e << result; logger()->error(e); result = 0; } return result; } /************************************************************************** * Class implementation: FormattingInfo **************************************************************************/ void FormattingInfo::clear() { mMinLength = 0; mMaxLength = INT_MAX; mLeftAligned = false; }; QString FormattingInfo::intToString(int i) { if (i == INT_MAX) return QLatin1String("INT_MAX"); else return QString::number(i); } /************************************************************************** * Class implementation: PatternConverter **************************************************************************/ void PatternConverter::format(QString &rFormat, const LoggingEvent &rLoggingEvent) const { const QLatin1Char space(' '); QString s = convert(rLoggingEvent); if (s.length() > mFormattingInfo.mMaxLength) rFormat += s.left(mFormattingInfo.mMaxLength); else if (mFormattingInfo.mLeftAligned) rFormat += s.leftJustified(mFormattingInfo.mMinLength, space, false); else rFormat += s.rightJustified(mFormattingInfo.mMinLength, space, false); } /************************************************************************** * Class implementation: BasicPatternConverter **************************************************************************/ QString BasicPatternConverter::convert(const LoggingEvent &rLoggingEvent) const { switch (mType) { case MESSAGE_CONVERTER: return rLoggingEvent.message(); break; case NDC_CONVERTER: return rLoggingEvent.ndc(); break; case LEVEL_CONVERTER: return rLoggingEvent.level().toString(); break; case THREAD_CONVERTER: return rLoggingEvent.threadName(); break; default: Q_ASSERT_X(false, "BasicPatternConverter::convert()", "Unkown type constant"); return QString(); } } QDebug BasicPatternConverter::debug(QDebug &rDebug) const { QString type; switch (mType) { case MESSAGE_CONVERTER: type = QLatin1String("MESSAGE_CONVERTER"); break; case NDC_CONVERTER: type = QLatin1String("NDC_CONVERTER"); break; case LEVEL_CONVERTER: type = QLatin1String("LEVEL_CONVERTER"); break; case THREAD_CONVERTER: type = QLatin1String("THREAD_CONVERTER"); break; default: Q_ASSERT_X(false, "BasicPatternConverter::debug()", "Unkown type constant"); } rDebug.nospace() << "BasicPatternConverter(" << mFormattingInfo << "type:" << type << ")"; return rDebug.space(); } /************************************************************************** * Class implementation: DatePatternConverter **************************************************************************/ QString DatePatternConverter::convert(const LoggingEvent &rLoggingEvent) const { return DateTime::fromMilliSeconds(rLoggingEvent.timeStamp()).toString(mFormat); } QDebug DatePatternConverter::debug(QDebug &rDebug) const { rDebug.nospace() << "DatePatternConverter(" << mFormattingInfo << "format:" << mFormat << ")"; return rDebug.space(); } /************************************************************************** * Class implementation: LiteralPatternConverter **************************************************************************/ QString LiteralPatternConverter::convert(const LoggingEvent &rLoggingEvent) const { Q_UNUSED(rLoggingEvent); return mLiteral; }; QDebug LiteralPatternConverter::debug(QDebug &rDebug) const { rDebug.nospace() << "LiteralPatternConverter(" << mFormattingInfo << "literal:" << mLiteral << ")"; return rDebug.space(); } /************************************************************************** * Class implementation: LoggerPatternConverter **************************************************************************/ QString LoggerPatternConverter::convert(const LoggingEvent &rLoggingEvent) const { if (!rLoggingEvent.logger()) return QString(); QString name = rLoggingEvent.logger()->name(); if (mPrecision <= 0 || (name.isEmpty())) return name; const QString separator(QLatin1String("::")); int i = mPrecision; int begin = name.length(); while ((i > 0) && (begin >= 0)) { begin = name.lastIndexOf(separator, begin - name.length() - 1); i--; } if (begin < 0) begin = 0; else begin += 2; return name.mid(begin); } QDebug LoggerPatternConverter::debug(QDebug &rDebug) const { rDebug.nospace() << "LoggerPatternConverter(" << mFormattingInfo << "precision:" << mPrecision << ")"; return rDebug.space(); } /****************************************************************************** * Class implementation: MDCPatternConverter ******************************************************************************/ QString MDCPatternConverter::convert(const LoggingEvent &rLoggingEvent) const { return rLoggingEvent.mdc().value(mKey); }; QDebug MDCPatternConverter::debug(QDebug &rDebug) const { rDebug.nospace() << "MDCPatternConverter(" << mFormattingInfo << "key:" << mKey << ")"; return rDebug.space(); } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const PatternFormatter &rPatternFormatter) { debug.nospace() << "PatternFormatter(" << "pattern:" << rPatternFormatter.mPattern << " " << "converters:("; int i; for (i = 0; i < rPatternFormatter.mPatternConverters.size(); i++) { if (i > 0) debug.nospace() << ", "; debug.nospace() << *rPatternFormatter.mPatternConverters.at(i); } debug.nospace() << ") )"; return debug.space(); } #endif #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const FormattingInfo &rFormattingInfo) { debug.nospace() << "FormattingInfo(" << "min:" << FormattingInfo::intToString(rFormattingInfo.mMinLength) << " " << "max:" << FormattingInfo::intToString(rFormattingInfo.mMaxLength) << " " << "left:" << rFormattingInfo.mLeftAligned << ")"; return debug.space(); } #endif // QT_NO_DEBUG_STREAM #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const PatternConverter &rPatternConverter) { return rPatternConverter.debug(debug); } #endif // QT_NO_DEBUG_STREAM } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/helpers/logerror.h0000664000175000017500000004141715167726064021321 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: logerror.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_LOGERROR_H #define LOG4QT_LOGERROR_H /****************************************************************************** * Dependencies ******************************************************************************/ #include #include #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * Creates an LogError object with the error message \a message, the error * code \a code and the context \a context. The symbol of the error is * set to \a code as string value. * * The following example logs an error, if a character is not a digit. * * \code * if (!c.isDigit()) * { * Error e = LOG4QT_ERROR(QT_TR_NOOP("Found character '%1' where digit was expected."), * LAYOUT_EXPECTED_DIGIT_ERROR, * "Log4Qt::PatternFormatter"); * e << QString(c); * logger()->error(e); * } * \endcode */ #define LOG4QT_ERROR(message, code, context) \ LogError(message, code, #code, context) /*! * Creates an LogError object with the error message \a message and the * error code \a code. The symbol of the error is set to \a code as string * value. The context is set to the class name of the current object. The * current objects class must be derived from QObject. * * The following example handles an error while opening a file. * * \code * if (!mpFile->open(mode)) * { * LogError e = LOG4QT_QCLASS_ERROR(QT_TR_NOOP("Unable to open file '%1' for appender '%2'"), * APPENDER_OPENING_FILE_ERROR); * e << mFileName << name(); * e.addCausingError(LogError(mpFile->errorString(), mpFile->error())); * logger()->error(e); * return; * } * \endcode */ #define LOG4QT_QCLASS_ERROR(message, code) \ LogError(message, code, #code, this->metaObject()->className()) /*! * \brief The class LogError represents an error. * * The class error allows storing error information in a structured way. * The error message is stored separately from the information that may be * substituted into the message string. This way it is possible to access * all information after the error has been raised. It also allows to * translate the error at a later point in time or to get a translated and * a not translated error text (e.g. translated for the UI and not * translated for a log). * * The message is accessed using message() and setMessage(). Arguments for * the message can be added using addArg() or operator<<(). The arguments * can be retrieved using args(). The message with substituted arguments * is returned by messageWithArgs(). * * An error code can be set as integer value code() and/or a symbolic value * symbol(). * * To allow the translation of the message the error stores the translation * context (context(), setContext()). The translated message can be accessed * using translatedMessage() or using translatedMessageWithArgs(), if it * should contain the arguments. * * An error can have one or more related errors that caused it. An error is * related using addCausingError(). All causing errors can be retrieved using * causingErrors(). * * A per thread error can be maintained using lastError() and setLastError(). * * There are two macros avaiable to simplify the error creation. The macro * \ref Log4Qt::LOG4QT_ERROR "LOG4QT_ERROR" is used with classes not derived * from QObject. The macro \ref Log4Qt::LOG4QT_QCLASS_ERROR "LOG4QT_QCLASS_ERROR" * is used with classes derived from QObject. */ class LIBUKUILOG4QT_EXPORT LogError { public: /*! * The enum Encoding defines the 8-bit encoding of a character string * arguments to \ref LogError::LogError(const char *, int, const char *, * const char *, Encoding) "LogError::LogError()". * * \sa \ref LogError::LogError(const char *, int, const char *, const char *, Encoding) "LogError::LogError()" */ enum Encoding { /*! LATIN-1 */ LATIN1, /*! * The encoding specified by QTextCodec::codecForTr() * (Latin-1 if none has been set). */ CODECFORTR, /*! UTF-8 */ UNICODEUTF8 }; Q_ENUMS(Encoding) /*! * Creates an empty error. The error code is set to 0 and all other * members are set to be empty. * * \sa isEmpty() */ LogError(); /*! * Creates an error with the Message \a rMessage and the error code * \a code. The symbol for the error code is set to \a rSymbol and the * context to \a rContext. * * \a rContext must be string that can be converted to Latin-1. The * Latin-1 representation of the string is used with * QApplication::translate(), if a translation for \a rMessage is * requested. * * \sa translatedMessage(), translatedMessageWithArgs() */ LogError(const QString &rMessage, int code = 0, const QString &rSymbol = QString(), const QString &rContext = QString()); /*! * Creates an error with the Message \a pMessage and the error code * \a code. The symbol for the error code is set to \a pSymbol and the * context to \a pContext. * * \a encoding specifies the encoding of \a pMessage. \a pSymbol and * \a pContext are expected to be Latin-1. * * \note To support the macros \ref Log4Qt::LOG4QT_ERROR "LOG4QT_ERROR" * and \ref Log4Qt::LOG4QT_QCLASS_ERROR "LOG4QT_QCLASS_ERROR" * the function tests, if \a pSymbol is the string representation of * \a code. If it is, the symbol is set to be empty. Otherwise symbol * is set to \a pSymbol. * * \sa translatedMessage(), translatedMessageWithArgs() */ LogError(const char *pMessage, int code = 0, const char *pSymbol = 0, const char *pContext = 0, Encoding encoding = LATIN1); // LogError(const LogError &rOther); // Use compiler default // virtual ~LogError(); // Use compiler default // LogError &operator=(const LogError &rOther); // Use compiler default /*! * Returns the error code. * * \sa setCode() */ int code() const; /*! * Returns the context for the error. * * \sa setContext() */ QString context() const; /*! * Returns the error message. * * \sa setMessage() */ QString message() const; /*! * Returns the symbol for the error code. * * \sa setSymbol() */ QString symbol() const; /*! * Returns the translated error message. * * The translated message is created by calling * QCoreApplication::translate() using context().toLatin1() as * context and message.toUtf8() as message. * * \sa translatedMessageWithArgs() */ QString translatedMessage() const; /*! * Sets the error code to \a code. * * \sa code() */ void setCode(int code); /*! * Sets the context to \a rClassName. * * \a rContext must be string that can be converted to Latin-1. The * Latin-1 representation of the string is used with * QApplication::translate(), if a translation for \a rMessage is * requestd. * * \sa context(), translatedMessage(), translatedMessageWithArgs() */ void setContext(const QString &rClassName); /*! * Sets the error message to \a rMessage * * \sa message() */ void setMessage(const QString &rMessage); /*! * Sets the symbol for the error code to \a rSymbol. * * \sa symbol() */ void setSymbol(const QString &rSymbol); /*! * Returns the last error set for the current thread using * setLastError(). * * \note: This function is thread-safe. * * \sa setLastError() */ static LogError lastError(); /*! * Sets the last error for the current thread to \a rLogError. * * \note: This function is thread-safe. * * \sa lastError() */ static void setLastError(const LogError &rLogError); /*! * Appends \a rArg to the list of arguments and returns a reference to * this error. * * \sa operator<<(), args(), clearArgs() */ LogError &addArg(const QVariant &rArg); /*! * This is an overloaded member function, provided for convenience. */ LogError &addArg(int arg); /*! * This is an overloaded member function, provided for convenience. */ LogError &addArg(const QString &rArg); /*! * Appends \a rLogError to the list of causing errors and returns a * reference to this error. * * \sa causingErrors(), clearCausingErrors() */ LogError &addCausingError(const LogError &rLogError); /*! * Returns the list of arguments that have been added to this error. * * \sa addArg(), operator<<(), clearArgs() */ QList args() const; /*! * Returns the list of causing errors that have been added to this error. * * \sa addArg(), operator<<(), clearArgs() */ QList causingErrors() const; /*! * Clears the list of arguments that have been added to this error. * * \sa addArg(), operator<<(), args() */ void clearArgs(); /*! * Clears the list of causing errors that have been added to this error. * * \sa addCausingError(), causingErrors() */ void clearCausingErrors(); /*! * Returns true, if the error code is 0 and the message is empty. * Otherwise it returns false. * * \sa code(), message() */ bool isEmpty() const; /*! * Returns the message with arguments. The arguments are incoorporated * into the messag using QString::arg(). * * \sa QString::arg(), translatedMessageWithArgs() */ QString messageWithArgs() const; /*! * Returns the translated message with arguments. The arguments are * incoorporated into the messag using QString::arg(). * * \sa QString::arg(), messageWithArgs(), translatedMessage() */ QString translatedMessageWithArgs() const; /*! * Appends \a rArg to the list of arguments and returns a reference to * this error. * * \sa addArg() */ LogError &operator<<(const QVariant &rArg); /*! * This is an overloaded member function, provided for convenience. */ LogError &operator<<(int arg); /*! * This is an overloaded member function, provided for convenience. */ LogError &operator<<(const QString &rArg); /*! * Returns a string representation of the error. * * The string has the following format: * * * message (context::symbol, code): causing_error, causing_error * * * If members are empty they are omitted: * - Omit context, if empty * - Omit symbol, if empty * - Omit double colon with context and symbol, if both are empty * - Omit code, if 0 * - Omit bracket with context/symbol and code, if all are empty * - Omit colon with causing errors, if no causing errors exist */ QString toString() const; private: QString insertArgs(const QString &rMessage) const; QString cleanMessage(const QString &rMessage); private: int mCode; QString mContext; QString mMessage; QString mSymbol; QList mArgs; QList mCausingErrors; #ifndef QT_NO_DATASTREAM // Needs to be friend to stream objects friend QDataStream &operator<<(QDataStream &rStream, const LogError &rLogError); friend QDataStream &operator>>(QDataStream &rStream, LogError &rLogError); #endif // QT_NO_DATASTREAM }; /************************************************************************** * Operators, Helper **************************************************************************/ #ifndef QT_NO_DATASTREAM /*! * \relates LogError * * Writes the given error \a rLogError to the given stream \a rStream, * and returns a reference to the stream. */ QDataStream &operator<<(QDataStream &rStream, const LogError &rLogError); /*! * \relates LogError * * Reads an error from the given stream \a rStream into the given * error \a rLogError, and returns a reference to the stream. */ QDataStream &operator>>(QDataStream &rStream, LogError &rLogError); #endif // QT_NO_DATASTREAM #ifndef QT_NO_DEBUG_STREAM /*! * \relates LogError * * Writes all object member variables to the given debug stream \a debug and * returns the stream. * * * %LogError(code:7 context:"Log4Qt::FileAppender" * message:"Unable to open file '%1' for appender '%2'" * symbol:"APPENDER_OPENING_FILE_ERROR" * args:(QVariant(QString, "G:\logs\client.log") , QVariant(QString, "Client FileAppender") ) * translatedMessage: "Unable to open file '%1' for appender '%2'" ) * * * \sa QDebug */ QDebug operator<<(QDebug debug, const LogError &rLogError); #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Inline **************************************************************************/ inline int LogError::code() const { return mCode; } inline QString LogError::context() const { return mContext; } inline QString LogError::message() const { return mMessage; } inline QString LogError::symbol() const { return mSymbol; } inline void LogError::setCode(int code) { mCode = code; } inline void LogError::setContext(const QString &rContext) { mContext = rContext; } inline void LogError::setMessage(const QString &rMessage) { mMessage = cleanMessage(rMessage); } inline void LogError::setSymbol(const QString &rSymbol) { mSymbol = rSymbol; } inline LogError &LogError::addArg(const QVariant &rArg) { mArgs << rArg; return *this; } inline LogError &LogError::addArg(int arg) { mArgs << QVariant(arg); return *this; } inline LogError &LogError::addArg(const QString &rArg) { mArgs << QVariant(rArg); return *this; } inline LogError &LogError::addCausingError(const LogError &rLogError) { mCausingErrors << rLogError; return *this; } inline QList LogError::args() const { return mArgs; } inline void LogError::clearArgs() { mArgs.clear(); } inline void LogError::clearCausingErrors() { mCausingErrors.clear(); } inline QList LogError::causingErrors() const { return mCausingErrors; } inline bool LogError::isEmpty() const { return mCode || !mMessage.isEmpty(); } inline QString LogError::messageWithArgs() const { return insertArgs(message()); } inline QString LogError::translatedMessageWithArgs() const { return insertArgs(translatedMessage()); } inline LogError &LogError::operator<<(const QVariant &rArg) { return addArg(rArg); } inline LogError &LogError::operator<<(int arg) { return addArg(arg); } inline LogError &LogError::operator<<(const QString &rArg) { return addArg(rArg); } } // namespace Log4Qt Q_DECLARE_METATYPE(Log4Qt::LogError) Q_DECLARE_TYPEINFO(Log4Qt::LogError, Q_MOVABLE_TYPE); #endif // LOG4QT_ERROR_H ukui-interface/src/log4qt/log4qt/helpers/factory.cpp0000664000175000017500000003771715167726064021500 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: factory.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/helpers/factory.h" #include #include #include #include "log4qt/consoleappender.h" #include "log4qt/dailyrollingfileappender.h" #include "log4qt/fileappender.h" #include "log4qt/helpers/logerror.h" #include "log4qt/helpers/initialisationhelper.h" #include "log4qt/helpers/optionconverter.h" #include "log4qt/patternlayout.h" #include "log4qt/rollingfileappender.h" #include "log4qt/simplelayout.h" #include "log4qt/ttcclayout.h" #include "log4qt/varia/debugappender.h" #include "log4qt/varia/denyallfilter.h" #include "log4qt/varia/levelmatchfilter.h" #include "log4qt/varia/levelrangefilter.h" #include "log4qt/varia/listappender.h" #include "log4qt/varia/nullappender.h" #include "log4qt/varia/stringmatchfilter.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ LOG4QT_DECLARE_STATIC_LOGGER(logger, Log4Qt::Factory) // Appenders Appender *console_file_appender() { return new ConsoleAppender; } Appender *create_daily_rolling_file_appender() { return new DailyRollingFileAppender; } Appender *create_debug_appender() { return new DebugAppender; } Appender *create_file_appender() { return new FileAppender; } Appender *create_list_appender() { return new ListAppender; } Appender *create_null_appender() { return new NullAppender; } Appender *create_rolling_file_appender() { return new RollingFileAppender; } // Filters Filter *create_deny_all_filter() { return new DenyAllFilter; } Filter *create_level_match_filter() { return new LevelMatchFilter; } Filter *create_level_range_filter() { return new LevelRangeFilter; } Filter *create_string_match_filter() { return new StringMatchFilter; } // Layouts Layout *create_pattern_layout() { return new PatternLayout; } Layout *create_simple_layout() { return new SimpleLayout; } Layout *create_ttcc_layout() { return new TTCCLayout; } /************************************************************************** * Class implementation: Factory **************************************************************************/ Factory::Factory() : mObjectGuard(), mAppenderRegistry(), mFilterRegistry(), mLayoutRegistry() { registerDefaultAppenders(); registerDefaultFilters(); registerDefaultLayouts(); } LOG4QT_IMPLEMENT_INSTANCE(Factory) Appender *Factory::doCreateAppender(const QString &rAppenderClassName) { QMutexLocker locker(&mObjectGuard); if (!mAppenderRegistry.contains(rAppenderClassName)) { logger()->warn("Request for the creation of Appender with class '%1', which is not registered", rAppenderClassName); return 0; } return mAppenderRegistry.value(rAppenderClassName)(); } Filter *Factory::doCreateFilter(const QString &rFilterClassName) { QMutexLocker locker(&mObjectGuard); if (!mFilterRegistry.contains(rFilterClassName)) { logger()->warn("Request for the creation of Filter with class '%1', which is not registered", rFilterClassName); return 0; } return mFilterRegistry.value(rFilterClassName)(); } Layout *Factory::doCreateLayout(const QString &rLayoutClassName) { QMutexLocker locker(&mObjectGuard); if (!mLayoutRegistry.contains(rLayoutClassName)) { logger()->warn("Request for the creation of Layout with class '%1', which is not registered", rLayoutClassName); return 0; } return mLayoutRegistry.value(rLayoutClassName)(); } void Factory::doRegisterAppender(const QString &rAppenderClassName, AppenderFactoryFunc pAppenderFactoryFunc) { QMutexLocker locker(&mObjectGuard); if(rAppenderClassName.isEmpty()) { logger()->warn("Registering Appender factory function with empty class name"); return; } mAppenderRegistry.insert(rAppenderClassName, pAppenderFactoryFunc); } void Factory::doRegisterFilter(const QString &rFilterClassName, FilterFactoryFunc pFilterFactoryFunc) { QMutexLocker locker(&mObjectGuard); if(rFilterClassName.isEmpty()) { logger()->warn("Registering Filter factory function with empty class name"); return; } mFilterRegistry.insert(rFilterClassName, pFilterFactoryFunc); } void Factory::doRegisterLayout(const QString &rLayoutClassName, LayoutFactoryFunc pLayoutFactoryFunc) { QMutexLocker locker(&mObjectGuard); if(rLayoutClassName.isEmpty()) { logger()->warn("Registering Layout factory function with empty class name"); return; } mLayoutRegistry.insert(rLayoutClassName, pLayoutFactoryFunc); } void Factory::doSetObjectProperty(QObject *pObject, const QString &rProperty, const QString &rValue) { // - Validate property // - Get correct property name from meta object // - Find specific property setter // - If no specfifc propery setter can be found, // find general property setter // - Call property setter QMetaProperty meta_property; if (!validateObjectProperty(meta_property, rProperty, pObject)) return; QString property = QLatin1String(meta_property.name()); QString type = QLatin1String(meta_property.typeName()); logger()->debug("Setting property '%1' on object of class '%2' to value '%3'", property, QLatin1String(pObject->metaObject()->className()), rValue); QVariant value; bool ok = true; if (type == QLatin1String("bool")) value = OptionConverter::toBoolean(rValue, &ok); else if (type == QLatin1String("int")) value = OptionConverter::toInt(rValue, &ok); else if (type == QLatin1String("qint64") || type == QLatin1String("qlonglong")) value = OptionConverter::toQInt64(rValue, &ok); else if (type == QLatin1String("Log4Qt::Level")) value = QVariant::fromValue(OptionConverter::toLevel(rValue, &ok)); else if (type == QLatin1String("QString")) value = rValue; else { LogError e = LOG4QT_ERROR(QT_TR_NOOP("Cannot convert to type '%1' for property '%2' on object of class '%3'"), CONFIGURATOR_UNKNOWN_TYPE_ERROR, "Log4Qt::Factory"); e << type << property << QString::fromLatin1(pObject->metaObject()->className()); logger()->error(e); return; } if (!ok) return; // Everything is checked and the type is the one of the property. // Write should never return false if (!meta_property.write(pObject, value)) logger()->warn("Unxpected error result from QMetaProperty.write()"); } void Factory::doUnregisterAppender(const QString &rAppenderClassName) { QMutexLocker locker(&mObjectGuard); if (!mAppenderRegistry.contains(rAppenderClassName)) { logger()->warn("Request to unregister not registered Appender factory function for class '%1'", rAppenderClassName); return; } mAppenderRegistry.remove(rAppenderClassName); } void Factory::doUnregisterFilter(const QString &rFilterClassName) { QMutexLocker locker(&mObjectGuard); if (!mFilterRegistry.contains(rFilterClassName)) { logger()->warn("Request to unregister not registered Filter factory function for class '%1'", rFilterClassName); return; } mFilterRegistry.remove(rFilterClassName); } void Factory::doUnregisterLayout(const QString &rLayoutClassName) { QMutexLocker locker(&mObjectGuard); if (!mLayoutRegistry.contains(rLayoutClassName)) { logger()->warn("Request to unregister not registered Layout factory function for class '%1'", rLayoutClassName); return; } mLayoutRegistry.remove(rLayoutClassName); } void Factory::registerDefaultAppenders() { mAppenderRegistry.insert(QLatin1String("org.apache.log4j.ConsoleAppender"), console_file_appender); mAppenderRegistry.insert(QLatin1String("Log4Qt::ConsoleAppender"), console_file_appender); mAppenderRegistry.insert(QLatin1String("org.apache.log4j.DailyRollingFileAppender"), create_daily_rolling_file_appender); mAppenderRegistry.insert(QLatin1String("Log4Qt::DailyRollingFileAppender"), create_daily_rolling_file_appender); mAppenderRegistry.insert(QLatin1String("org.apache.log4j.varia.DebugAppender"), create_debug_appender); mAppenderRegistry.insert(QLatin1String("Log4Qt::DebugAppender"), create_debug_appender); mAppenderRegistry.insert(QLatin1String("org.apache.log4j.FileAppender"), create_file_appender); mAppenderRegistry.insert(QLatin1String("Log4Qt::FileAppender"), create_file_appender); mAppenderRegistry.insert(QLatin1String("org.apache.log4j.varia.ListAppender"), create_list_appender); mAppenderRegistry.insert(QLatin1String("Log4Qt::ListAppender"), create_list_appender); mAppenderRegistry.insert(QLatin1String("org.apache.log4j.varia.NullAppender"), create_null_appender); mAppenderRegistry.insert(QLatin1String("Log4Qt::NullAppender"), create_null_appender); mAppenderRegistry.insert(QLatin1String("org.apache.log4j.RollingFileAppender"), create_rolling_file_appender); mAppenderRegistry.insert(QLatin1String("Log4Qt::RollingFileAppender"), create_rolling_file_appender); } void Factory::registerDefaultFilters() { mFilterRegistry.insert(QLatin1String("org.apache.log4j.varia.DenyAllFilter"), create_deny_all_filter); mFilterRegistry.insert(QLatin1String("Log4Qt::DenyAllFilter"), create_deny_all_filter); mFilterRegistry.insert(QLatin1String("org.apache.log4j.varia.LevelMatchFilter"), create_level_match_filter); mFilterRegistry.insert(QLatin1String("Log4Qt::LevelMatchFilter"), create_level_match_filter); mFilterRegistry.insert(QLatin1String("org.apache.log4j.varia.LevelRangeFilter"), create_level_range_filter); mFilterRegistry.insert(QLatin1String("Log4Qt::LevelRangeFilter"), create_level_range_filter); mFilterRegistry.insert(QLatin1String("org.apache.log4j.varia.StringMatchFilter"), create_string_match_filter); mFilterRegistry.insert(QLatin1String("Log4Qt::StringMatchFilter"), create_string_match_filter); } void Factory::registerDefaultLayouts() { mLayoutRegistry.insert(QLatin1String("org.apache.log4j.PatternLayout"), create_pattern_layout); mLayoutRegistry.insert(QLatin1String("Log4Qt::PatternLayout"), create_pattern_layout); mLayoutRegistry.insert(QLatin1String("org.apache.log4j.SimpleLayout"), create_simple_layout); mLayoutRegistry.insert(QLatin1String("Log4Qt::SimpleLayout"), create_simple_layout); mLayoutRegistry.insert(QLatin1String("org.apache.log4j.TTCCLayout"), create_ttcc_layout); mLayoutRegistry.insert(QLatin1String("Log4Qt::TTCCLayout"), create_ttcc_layout); } bool Factory::validateObjectProperty(QMetaProperty &rMetaProperty, const QString &rProperty, QObject *pObject) { // Validate: // - No null object pointer // - No empty property name // - Property exists on the object (QT or Java name) // - Property is readable // - Property is writable const char *p_context = "Log4Qt::Factory"; LogError e = LOG4QT_ERROR(QT_TR_NOOP("Unable to set property value on object"), CONFIGURATOR_PROPERTY_ERROR, p_context); if (!pObject) { LogError ce = LOG4QT_ERROR(QT_TR_NOOP("Invalid null object pointer"), 0, p_context); e.addCausingError(ce); logger()->error(e); return false; } if (rProperty.isEmpty()) { LogError ce = LOG4QT_ERROR(QT_TR_NOOP("Invalid empty property name"), 0, p_context); e.addCausingError(ce); logger()->error(e); return false; } const QMetaObject *p_meta_object = pObject->metaObject(); QString property = rProperty; int i = p_meta_object->indexOfProperty(property.toLatin1()); if (i < 0) { // Try name with lower case first character. Java properties names // start upper case property[0] = property[0].toLower(); i = p_meta_object->indexOfProperty(property.toLatin1()); if (i < 0) { LogError ce = LOG4QT_ERROR(QT_TR_NOOP("Property '%1' does not exist in class '%2'"), 0, p_context); ce << property << QString::fromLatin1(pObject->metaObject()->className()); e.addCausingError(ce); logger()->error(e); return false; } } rMetaProperty = p_meta_object->property(i); if (!rMetaProperty.isWritable()) { LogError ce = LOG4QT_ERROR(QT_TR_NOOP("Property '%1' is not writable in class '%2'"), 0, p_context); ce << property << QString::fromLatin1(pObject->metaObject()->className()); e.addCausingError(ce); logger()->error(e); return false; } return true; } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const Factory &rFactory) { debug.nospace() << "Factory(" << "appenderfactories:" << rFactory.registeredAppenders() << "filterfactories:" << rFactory.registeredFilters() << "layoutfactories:" << rFactory.registeredLayouts() << ")"; return debug.space(); } #endif // QT_NO_DEBUG_STREAM } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/helpers/logobjectptr.cpp0000664000175000017500000000363015167726064022512 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: logobjectptr.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/helpers/logobjectptr.h" #include namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: LogObjectPtr **************************************************************************/ /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/helpers/classlogger.h0000664000175000017500000000715115167726076021773 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: classlogger.h * created: September 2007 * author: Martin Heinrich * * * changes: Sep 2008, Martin Heinrich: * - Replaced usage of q_atomic_test_and_set_ptr with * QAtomicPointer * * * Copyright 2007 - 2008 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_CLASSLOGGER_H #define LOG4QT_CLASSLOGGER_H #include "ukui-logmacros.h" /****************************************************************************** * Dependencies ******************************************************************************/ #include #if QT_VERSION >= 0x040400 && QT_VERSION < 0x060000 # include # ifndef Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE # warning "QAtomicPointer test and set is not native. The class Log4Qt::ClassLogger is not thread-safe." # endif #elif QT_VERSION >= 0x060000 # include #endif /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { class Logger; /*! * \brief The class ClassLogger provides logging for a QObject derived * class. * * The class ClassLogger provides a logger for a specified QObject derived * object. It is used by \ref LOG4QT_DECLARE_QCLASS_LOGGER to implement the * member functions provided by the macro. * * \note All the functions declared in this class are thread-safe. * * \sa LOG4QT_DECLARE_QCLASS_LOGGER */ class LIBUKUILOG4QT_EXPORT ClassLogger { public: /*! * Creates a ClassLogger object. */ ClassLogger(); // ~ClassLogger(); // Use compiler default // ClassLogger(const ClassLogger &rOther); // Use compiler default // ClassLogger &operator=(const ClassLogger &rOther); // Use compiler default /*! * Returns a pointer to a Logger named after the class of the object * \a pObject. * * On the first invocation the Logger is requested by a call to * LogManager::logger(const char *pName). The pointer is stored to be * returned on subsequent invocations. * * \sa LogManager::logger(const char *pName) */ Logger *logger(const QObject *pObject); private: #if QT_VERSION < 0x040400 volatile Logger *mpLogger; #elif QT_VERSION < 0x060000 mutable QAtomicPointer mpLogger; #else mutable std::atomic mpLogger; #endif }; /****************************************************************************** * Operators, Helper ******************************************************************************/ /************************************************************************** * Inline **************************************************************************/ } // namespace Log4Qt // Q_DECLARE_TYPEinfo(Log4Qt::ClassLogger, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_CLASSLOGGER_H ukui-interface/src/log4qt/log4qt/helpers/asyncdispatcher.cpp0000664000175000017500000000260715167726064023203 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see namespace Log4Qt { AsyncDispatcher::AsyncDispatcher(QObject *parent) : QObject(parent) , mAsyncAppender(nullptr) {} void AsyncDispatcher::customEvent(QEvent *event) { if (event->type() == LoggingEvent::eventId) { auto *logEvent = static_cast(event); if (mAsyncAppender != nullptr) mAsyncAppender->asyncAppend(*logEvent); } QObject::customEvent(event); } void AsyncDispatcher::setAsyncAppender(AppenderSkeleton *asyncAppender) { mAsyncAppender = asyncAppender; } } // namespace Log4Qtukui-interface/src/log4qt/log4qt/helpers/logerror.cpp0000664000175000017500000002316715167726076021661 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: logerror.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies *****************************************************************************/ #include "log4qt/helpers/logerror.h" #include #include #include #include #include #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #include #endif #include #include "log4qt/helpers/initialisationhelper.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ typedef QThreadStorage ThreadError; /************************************************************************** * C helper functions **************************************************************************/ LOG4QT_GLOBAL_STATIC(ThreadError, thread_error) /************************************************************************** * Class implementation: LogError **************************************************************************/ LogError::LogError() : mCode(0), mContext(), mMessage(), mSymbol(), mArgs(), mCausingErrors() { } LogError::LogError(const QString &rMessage, int code, const QString &rSymbol, const QString &rContext) : mCode(code), mContext(rContext), mMessage(cleanMessage(rMessage)), mSymbol(rSymbol), mArgs(), mCausingErrors() { } LogError::LogError(const char *pMessage, int code, const char *pSymbol, const char *pContext, Encoding encoding) : mCode(code), mContext(QString::fromLatin1(pContext)), mMessage(), mSymbol(QString::fromLatin1(pSymbol)), mArgs(), mCausingErrors() { switch(encoding) { case LATIN1: mMessage = QString::fromLatin1(pMessage); break; case CODECFORTR: #if QT_VERSION < 0x050000 mMessage = QTextCodec::codecForTr()->toUnicode(pMessage); #elif QT_VERSION < 0x060000 mMessage = QString::fromUtf8(pMessage); #else mMessage = QString::fromUtf8(pMessage); #endif break; case UNICODEUTF8: mMessage = QString::fromUtf8(pMessage); break; default: Q_ASSERT_X(false, "LogError::LogError", "Unkown encoding constant"); mMessage = QString::fromLatin1(pMessage); } mMessage = cleanMessage(mMessage); if (mSymbol == QString::number(mCode)) mSymbol.clear(); } QString LogError::translatedMessage() const { #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) return QCoreApplication::translate(mContext.toLatin1(), mMessage.toUtf8().data(), 0, QCoreApplication::UnicodeUTF8); #else return QCoreApplication::translate(mContext.toLatin1(), mMessage.toUtf8().data(), 0); #endif } LogError LogError::lastError() { if (!thread_error()->hasLocalData()) return LogError(); else return *thread_error()->localData(); } void LogError::setLastError(const LogError &rLogError) { if (!thread_error()->hasLocalData()) thread_error()->setLocalData(new LogError); *thread_error()->localData() = rLogError; } QString LogError::toString() const { QString result = messageWithArgs(); QString context_symbol = mContext; if (!context_symbol.isEmpty() && !mSymbol.isEmpty()) context_symbol.append(QLatin1String("::")); context_symbol.append(mSymbol); if (!context_symbol.isEmpty() || mCode) { result.append(QLatin1String(" (")); if (!context_symbol.isEmpty()) result.append(context_symbol); if (!context_symbol.isEmpty() && mCode) result.append(QLatin1String(", ")); if (mCode) result.append(QString::number(mCode)); result.append(QLatin1String(")")); } if (!mCausingErrors.isEmpty()) { QString causing_errors_str = QLatin1String(": ") + mCausingErrors.at(0).toString(); int i = 1; while (i < mCausingErrors.count()) { causing_errors_str.append(QLatin1String(", ")).append(mCausingErrors.at(i).toString()); i++; } result.append(causing_errors_str); } return QString(result); } QString LogError::insertArgs(const QString &rMessage) const { QString result; /* // Don't use a loop to be able to handle arguments that conatin strings // like %1. // Using this method only 9 arguments can be handled as the %1 // in %11 gets also replaced with the first argument. switch (mArgs.count()) { case 0: break; case 1: result = rMessage.arg(mArgs.at(0)); break; case 2: result = rMessage.arg(mArgs.at(0), mArgs.at(1)); break; case 3: result = rMessage.arg(mArgs.at(0), mArgs.at(1), mArgs.at(2)); break; case 4: result = rMessage.arg(mArgs.at(0), mArgs.at(1), mArgs.at(2), mArgs.at(3)); break; case 5: result = rMessage.arg(mArgs.at(0), mArgs.at(1), mArgs.at(2), mArgs.at(3), mArgs.at(4)); break; case 6: result = rMessage.arg(mArgs.at(0), mArgs.at(1), mArgs.at(2), mArgs.at(3), mArgs.at(4), mArgs.at(5)); break; case 7: result = rMessage.arg(mArgs.at(0), mArgs.at(1), mArgs.at(2), mArgs.at(3), mArgs.at(4), mArgs.at(5), mArgs.at(6)); break; case 8: result = rMessage.arg(mArgs.at(0), mArgs.at(1), mArgs.at(2), mArgs.at(3), mArgs.at(4), mArgs.at(5), mArgs.at(6), mArgs.at(7)); break; default: result = rMessage.arg(mArgs.at(0), mArgs.at(1), mArgs.at(2), mArgs.at(3), mArgs.at(4), mArgs.at(5), mArgs.at(6), mArgs.at(7), mArgs.at(8)); break; } if (mArgs.count() > 9) { int i = 9; while(i < mArgs.count()) { result = result.arg(mArgs.at(i)); i++; } } */ result = rMessage; QVariant arg; Q_FOREACH(arg, mArgs) result = result.arg(arg.toString()); return QString(result); } QString LogError::cleanMessage(const QString &rMessage) { if (rMessage.isEmpty()) return rMessage; QString result = rMessage; if (rMessage.at(rMessage.size() - 1) == QLatin1Char('.')) result = rMessage.left(rMessage.size() - 1); return QString(result); } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DATASTREAM QDataStream &operator<<(QDataStream &rStream, const LogError &rLogError) { QBuffer buffer; buffer.open(QIODevice::WriteOnly); QDataStream stream(&buffer); // version quint16 version = 0; stream << version; // version 0 data stream << rLogError.mCode << rLogError.mContext << rLogError.mMessage << rLogError.mSymbol << rLogError.mArgs << rLogError.mCausingErrors; buffer.close(); rStream << buffer.buffer(); return rStream; } QDataStream &operator>>(QDataStream &rStream, LogError &rLogError) { QByteArray array; rStream >> array; QBuffer buffer(&array); buffer.open(QIODevice::ReadOnly); QDataStream stream(&buffer); // version quint16 version; stream >> version; // Version 0 data QString level; QString logger; stream >> rLogError.mCode >> rLogError.mContext >> rLogError.mMessage >> rLogError.mSymbol >> rLogError.mArgs >> rLogError.mCausingErrors; buffer.close(); return rStream; } #endif // QT_NO_DATASTREAM #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const LogError &rLogError) { // Escape % sign QString message = rLogError.message(); message.replace(QLatin1String("%"), QLatin1String("%%")); debug.nospace() << "LogError(" << "code:" << rLogError.code() << " " << "context:" << rLogError.context() << " " << "message:" << message << " " << "symbol:" << rLogError.symbol() << " " << "args:" << rLogError.args() << "translatedMessage:" << rLogError.translatedMessage() << ")"; return debug.maybeSpace(); } #endif // QT_NO_DEBUG_STREAM } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/helpers/logobjectptr.h0000664000175000017500000001202715167726064022157 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: logobjectptr.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_LOGOBJECTPTR_H #define LOG4QT_LOGOBJECTPTR_H #include "ukui-logmacros.h" /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/helpers/logobject.h" namespace Log4Qt { /*! * \brief The class LogObjectPtr implements automatic reference counting * for LogObject objects. */ template class LIBUKUILOG4QT_EXPORT LogObjectPtr { public: /*! * Constructs a 0 LogObject pointer. */ LogObjectPtr(); /*! * Constructs a LogObject pointer that points to the same object then * \a rOther. The reference counter of the object is incremented by * one. */ LogObjectPtr(const LogObjectPtr &rOther); /*! * Constructs a LogObject pointer that points to the object * \a LogObject. The reference counter of the object is incremented by * one. */ LogObjectPtr(T *pLogObject); /*! * Assignment operator. Sets the LogObject pointer to point to the * same object that \a rOther points to. The reference counter of the * object the LogObjectPtr pointed to before the assignment is * decremented by one. The reference counter of the object \a rOther * is pointing to is incremented by one. */ LogObjectPtr &operator=(const LogObjectPtr &rOther); /*! * Destructs the object. The reference counter of the object the * LogObjectPtr points to is decremented by one. */ ~LogObjectPtr(); /*! * Assignment operator. Sets the LogObject pointer to point to the * object \a pLogObject. The reference counter of the object the * LogObjectPtr pointed to before the assignment is decremented by * one. The reference counter of the object \a pLogObject is pointing * to is incremented by one. */ LogObjectPtr &operator=(T *pLogObject); /*! * Arrow operator. Returns the LogObject the object points to. */ T *operator->() const; /*! * Dereference operator. Returns a pointer to the LogObject the * object points to. */ T &operator*() const; /*! * Cast operator. Cast the object to the LogObject the object points * to. */ operator T*() const; private: void retain() const; void release() const; private: T *mpLogObject; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ template inline LogObjectPtr::LogObjectPtr() : mpLogObject(0) {} template inline LogObjectPtr::LogObjectPtr(const LogObjectPtr &rOther) : mpLogObject(rOther.mpLogObject) { retain(); } template inline LogObjectPtr::LogObjectPtr(T *pLogObject) : mpLogObject(pLogObject) { retain(); } template inline LogObjectPtr &LogObjectPtr::operator=(const LogObjectPtr &rOther) { rOther.retain(); release(); mpLogObject = rOther.mpLogObject; return *this; } template inline LogObjectPtr::~LogObjectPtr() { release(); } template inline LogObjectPtr &LogObjectPtr::operator=(T *pLogObject) { if (pLogObject) reinterpret_cast(pLogObject)->retain(); release(); mpLogObject = pLogObject; return *this; } template inline T *LogObjectPtr::operator->() const { return mpLogObject; } template inline T &LogObjectPtr::operator*() const { return *mpLogObject; } template inline LogObjectPtr::operator T*() const { return mpLogObject; } template inline void LogObjectPtr::retain() const { if (mpLogObject) reinterpret_cast(mpLogObject)->retain(); } template inline void LogObjectPtr::release() const { if (mpLogObject) reinterpret_cast(mpLogObject)->release(); } } // namespace Log4Qt //Q_DECLARE_TYPEINFO(Log4Qt::LogObjectPtr, Q_MOVABLE_TYPE); // Declare within T #endif // LOG4QT_LOGOBJECTPTR_H ukui-interface/src/log4qt/log4qt/helpers/initialisationhelper.h0000664000175000017500000004336115167726076023711 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: initialisationhelper.h * created: September 2007 * author: Martin Heinrich * * * changes: Sep 2008, Martin Heinrich: * - Replaced usage of q_atomic_test_and_set_ptr with * QBasicAtomicPointer * * * Copyright 2007 - 2008 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_HELPERS_INITIALISATIONHELPER_H #define LOG4QT_HELPERS_INITIALISATIONHELPER_H /****************************************************************************** * Dependencies ******************************************************************************/ #if QT_VERSION < 0x060000 #include #endif #include #include #include "ukui-logmacros.h" #if QT_VERSION >= 0x040400 && QT_VERSION < 0x060000 # ifndef Q_ATOMIC_POINTER_TEST_AND_SET_IS_ALWAYS_NATIVE # warning "QAtomicPointer test and set is not native. The macros Log4Qt::LOG4QT_GLOBAL_STATIC and Log4Qt::LOG4QT_IMPLEMENT_INSTANCE are not thread-safe." # endif #endif /****************************************************************************** * Declarations ******************************************************************************/ class QMutex; namespace Log4Qt { /*! * LOG4QT_GLOBAL_STATIC declares a static function \a FUNCTION that * returns a pointer to a singleton object of the type \a TYPE. * * The macro uses a static variable to store a pointer to the singleton * object. On the first invocation an object of the type \a TYPE is created * on the heap and the pointer is set. Any further invocations will return * the stored pointer. If multiple threads are accessing the function * without the pointer being set, each thread will create an object of the * type \a TYPE. The threads that find the pointer already been set will * delete their object. The singleton object will not be deleted during static * de-initialisation. * * The following example uses a global global mutex object to synchronise * access to a static member variable. * * \code * #file: myclass.h * * class MyClass * { * public: * MyClass(); * ~MyClass(); * private: * static qint64 msObjectCount; * } * \endcode * \code * #file: myclass.cpp * * #include myclass.h * * LOG4QT_GLOBAL_STATIC(QMutex, class_guard) * * MyClass::MyClass() * { * QMutexLocker(class_guard()); * msObjectCount++; * } * * MyClass::~MyClass() * { * QMutexLocker(class_guard()); * msObjectCount--; * } * * qint64 MyClass::msObjectCount = 0; * \endcode * * \note The function created by the macro is thread-safe. * * \sa \ref Log4Qt::LOG4QT_IMPLEMENT_INSTANCE "LOG4QT_IMPLEMENT_INSTANCE", * \ref Log4Qt::InitialisationHelper "InitialisationHelper" */ #if QT_VERSION < QT_VERSION_CHECK(4, 4, 0) #define LOG4QT_GLOBAL_STATIC(TYPE, FUNCTION) \ static volatile TYPE *sp_global_static_##FUNCTION = 0; \ TYPE *FUNCTION() \ { \ if (!sp_global_static_##FUNCTION) \ { \ TYPE *p_temp = new TYPE; \ if (!q_atomic_test_and_set_ptr(&sp_global_static_##FUNCTION, \ 0, p_temp)) \ delete p_temp; \ } \ return const_cast(sp_global_static_##FUNCTION); \ } #elif QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #define LOG4QT_GLOBAL_STATIC(TYPE, FUNCTION) \ static QBasicAtomicPointer sp_global_static_##FUNCTION = \ Q_BASIC_ATOMIC_INITIALIZER(0); \ TYPE *FUNCTION() \ { \ if (!sp_global_static_##FUNCTION) \ { \ TYPE *p_temp = new TYPE; \ if (!sp_global_static_##FUNCTION.testAndSetOrdered(0, \ p_temp)) \ delete p_temp; \ } \ return sp_global_static_##FUNCTION; \ } #else #define LOG4QT_GLOBAL_STATIC(TYPE, FUNCTION) \ static QBasicAtomicPointer sp_global_static_##FUNCTION = \ Q_BASIC_ATOMIC_INITIALIZER(0); \ TYPE *FUNCTION() \ { \ if (!sp_global_static_##FUNCTION.loadAcquire()) \ { \ TYPE *p_temp = new TYPE; \ if (!sp_global_static_##FUNCTION.testAndSetOrdered(0, \ p_temp)) \ delete p_temp; \ } \ return sp_global_static_##FUNCTION.loadAcquire(); \ } #endif /*! * LOG4QT_IMPLEMENT_INSTANCE implements an instance function for a * singleton class \a TYPE. * * The function works like the one created by * \ref Log4Qt::LOG4QT_GLOBAL_STATIC "LOG4QT_GLOBAL_STATIC". * * The following example illustrates how to use the macro to create a * singleton class: * * \code * #file: mysingleton.h * * class MySingleton * { * private: * MySingleton(); * ~MySingleton(); * public: * MySingleton *instance(); * } * \endcode * \code * #file: mysingleton.cpp * * #include mysingleton.h * * MySingleton::MySingleton() * {} * * MySingleton::~MySingleton() * {} * * LOG4QT_IMPLEMENT_INSTANCE(MySingleton) * * \endcode * * \note The function created by the macro is thread-safe. * * \sa \ref Log4Qt::LOG4QT_GLOBAL_STATIC "LOG4QT_GLOBAL_STATIC", * \ref Log4Qt::InitialisationHelper "InitialisationHelper" */ #if QT_VERSION < QT_VERSION_CHECK(4, 4, 0) #define LOG4QT_IMPLEMENT_INSTANCE(TYPE) \ static TYPE *sp_singleton_##TYPE = 0; \ TYPE *TYPE::instance() \ { \ if (!sp_singleton_##TYPE) \ { \ TYPE *p_temp = new TYPE; \ if (!q_atomic_test_and_set_ptr(&sp_singleton_##TYPE, \ 0, p_temp)) \ delete p_temp; \ } \ return sp_singleton_##TYPE; \ } #elif QT_VERSION < QT_VERSION_CHECK(5, 0, 0) #define LOG4QT_IMPLEMENT_INSTANCE(TYPE) \ static QBasicAtomicPointer sp_singleton_##TYPE = \ Q_BASIC_ATOMIC_INITIALIZER(0); \ TYPE *TYPE::instance() \ { \ if (!sp_singleton_##TYPE) \ { \ TYPE *p_temp = new TYPE; \ if (!sp_singleton_##TYPE.testAndSetOrdered(0, p_temp)) \ delete p_temp; \ } \ return sp_singleton_##TYPE; \ } #else #define LOG4QT_IMPLEMENT_INSTANCE(TYPE) \ static QBasicAtomicPointer sp_singleton_##TYPE = \ Q_BASIC_ATOMIC_INITIALIZER(0); \ TYPE *TYPE::instance() \ { \ if (!sp_singleton_##TYPE.loadAcquire()) \ { \ TYPE *p_temp = new TYPE; \ if (!sp_singleton_##TYPE.testAndSetOrdered(0, p_temp)) \ delete p_temp; \ } \ return sp_singleton_##TYPE.loadAcquire(); \ } #endif /*! * \brief The class InitialisationHelper performs static initialisation * tasks. * * The InitialisationHelper is either created on the first call or through * static initialisation. It will capture the programs startup time, * which can be retrieved using startTime(). The system environment * is analysed for package related definitions. The result is available * over environmentSettings(). The packages custom types are registered with * the Qt type system. * * Settings for the package can be retrieved using setting(). Two macros * are available to help with the creation of singletons / global static * objects (\ref Log4Qt::LOG4QT_GLOBAL_STATIC "LOG4QT_GLOBAL_STATIC" and * \ref Log4Qt::LOG4QT_IMPLEMENT_INSTANCE "LOG4QT_IMPLEMENT_INSTANCE"). * * \note All the functions declared in this class are thread-safe. * * \sa \ref Init "Initialization procedure", */ class LIBUKUILOG4QT_EXPORT InitialisationHelper { private: InitialisationHelper(); InitialisationHelper(const InitialisationHelper &rOther); // Not implemented virtual ~InitialisationHelper(); InitialisationHelper &operator=(const InitialisationHelper &rOther); // Not implemented public: /*! * Returns a hash with the settings retrieved from the system * environment on startup. * * The following table shows the environment variables taken into * account and the setting key used for them. * * * * * * * * * * * * * * * * * * *
Environment variable Setting key
LOG4QT_DEBUG Debug
LOG4QT_DEFAULTINITOVERRIDE DefaultInitOverride
LOG4QT_CONFIGURATION Configuration
LOG4QT_CONFIGURATORCLASS ConfiguratorClass
* * \sa \ref Env "Environment Variables", * setting() */ static QHash environmentSettings(); /*! * Returns the InitialisationHelper instance. */ static InitialisationHelper *instance(); /*! * Returns the value for the setting \a rKey or \a rDefault, if it is * not defined. * * A setting can be either defined by an environment variable or by a * key in the application setting. The function will first test the * settings made by environment variables for the key \a rKey using * environmentSettings(). If the key is not present and a * QCoreApplication exists, the application settings are tested for * the key \a rKey in the group \c %Log4Qt. * * The following setting exists: * * * * * * * * * * * * * * * * * * *
Setting key Description
Debug The variable controls the Level value for the logger * LogManager::logLogger(). If the value is a valid Level string, * the level for the logger is set to the level. If the value is not * a valid Level string, \ref Level::DEBUG_INT "DEBUG_INT" is used. * Otherwise \ref Level::ERROR_INT "ERROR_INT" is used.
DefaultInitOverride The variable controls the \ref Init "initialization procedure" * performed by the \ref LogManager "LogManager" on startup. * If it is set to any other value then \c false the \ref Init * "initialization procedure" is skipped.
Configuration Specifies the configuration file used for initialising the package.
ConfiguratorClass Specifies the configurator class used for initialising the package.
* * \sa environmentSettings(), \ref Env "Environment Variables", * \ref Init "Initialization procedure", * LogManager::configureLogLogger(), LogManager::startup() */ static QString setting(const QString &rKey, const QString &rDefault = QString()); /*! * Returns the start time of the program as the number of milliseconds * that have passed since 1970-01-01T00:00:00,000, Coordinated * Universal Time (Qt::UTC). * * \sa DateTime::fromMilliSeconds(), * DateTime::toMilliSeconds() */ static qint64 startTime(); private: void doInitialiseEnvironmentSettings(); void doRegisterTypes(); QString doSetting(const QString &rKey, const QString &rDefault) const; static bool shutdown(); static bool staticInitialisation(); private: // QMutex mObjectGuard; const qint64 mStartTime; QHash mEnvironmentSettings; static bool msStaticInitialisation; #ifndef QT_NO_DEBUG_STREAM // Needs to be friend to access details friend QDebug operator<<(QDebug debug, const InitialisationHelper &rInitialisationHelper); #endif // QT_NO_DEBUG_STREAM }; /************************************************************************** * Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM /*! * \relates InitialisationHelper * * Writes all object member variables to the given debug stream \a rDebug and * returns the stream. * * * %InitialisationHelper(InitialisationHelper(starttime:1193883677438( * QDateTime("Wed Oct 31 21:21:17 2007") ) * environmentsettings: QHash(("configuration", "\myapp.log4j") * ("Debug", "DEBUG")) ) ) * * \sa QDebug, InitialisationHelper::logManager() */ QDebug operator<<(QDebug debug, const InitialisationHelper &rInitialisationHelper); #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Inline **************************************************************************/ inline QHash InitialisationHelper::environmentSettings() { // QMutexLocker locker(&instance()->mObjectGuard); // Constant for object lifetime return instance()->mEnvironmentSettings; } inline QString InitialisationHelper::setting(const QString &rKey, const QString &rDefault) { // QMutexLocker locker(&instance()->mObjectGuard); // Reentrant and const return instance()->doSetting(rKey, rDefault); } inline qint64 InitialisationHelper::startTime() { // QMutexLocker locker(&instance()->mObjectGuard); // Constant for object lifetime return instance()->mStartTime; } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::InitialisationHelper, Q_COMPLEX_TYPE); // use default #endif // LOG4QT_HELPERS_INITIALISATIONHELPER_H ukui-interface/src/log4qt/log4qt/helpers/factory.h0000664000175000017500000004237115167726064021135 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: factory.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_HELPERS_FACTORY_H #define LOG4QT_HELPERS_FACTORY_H /****************************************************************************** * Dependencies ******************************************************************************/ #include #include #include #include "ukui-logmacros.h" QT_BEGIN_NAMESPACE class QMetaProperty; class QObject; QT_END_NAMESPACE /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { class Appender; class Filter; class Layout; /*! * \brief The class Factory provides factories for Appender, Filter and * Layout objects. * * The functions createAppender(), createFilter() and createLayout() * allow to create objects by specifying their class names. By default * all classes of the package are recognised with their Log4j and Log4Qt * classanmes. For example an object of the class FileAppender can be * craeted using "org.apache.log4j.FileAppender" or "Log4Qt::FileAppender". * Additional classes can be registered using registerAppender(), * registerFilter() and registerLayout(). * * An QObject property can be set from a string value with * setObjectProperty(). The function handles the required error checking * and type conversion. * * \note All the functions declared in this class are thread-safe. * * \sa PropertyConfigurator */ class LIBUKUILOG4QT_EXPORT Factory { public: /*! * Prototype for an Appender factory function. The function creates * an Appender object on the heap and returns a pointer to it. * * \sa registerAppender(), createAppender() */ typedef Appender *(*AppenderFactoryFunc)(); /*! * Prototype for a Filter factory function. The function creates * a Filter object on the heap and returns a pointer to it. * * \sa registerFilter(), createFilter() */ typedef Filter *(*FilterFactoryFunc)(); /*! * Prototype for a Layout factory function. The function creates * a Layout object on the heap and returns a pointer to it. * * \sa registerLayout(), createLayout() */ typedef Layout *(*LayoutFactoryFunc)(); private: Factory(); Q_DISABLE_COPY(Factory) public: /*! * Creates an object for the class \a rAppenderClassName on the heap * and returns a pointer to it. If the class has no registered factory * function a null pointer is returned. * * \sa registerAppender(), unregisterAppender(), registeredAppenders() */ static Appender *createAppender(const QString &rAppenderClassName); /*! * This is an overloaded member function, provided for convenience. */ static Appender *createAppender(const char *pAppenderClassName); /*! * Creates an object for the class \a rFilterClassName on the heap * and returns a pointer to it. If the class has no registered factory * function a null pointer is returned. * * \sa registerFilter(), unregisterFilter(), registeredFilters() */ static Filter *createFilter(const QString &rFilterClassName); /*! * This is an overloaded member function, provided for convenience. */ static Filter *createFilter(const char *pFilterClassName); /*! * Creates an object for the class \a rLayoutClassName on the heap * and returns a pointer to it. If the class has no registered factory * function a null pointer is returned. * * \sa registerLayout(), unregisterLayout(), registeredLayouts() */ static Layout *createLayout(const QString &rLayoutClassName); /*! * This is an overloaded member function, provided for convenience. */ static Layout *createLayout(const char *pLayoutClassName); /*! * Returns the Factory instance. */ static Factory *instance(); /*! * Registers the Appender factory function \a pAppenderFactoryFunc * for the class \a rAppenderClassName. If a registered factory * function exists for the class, it is replaced with * \a pAppenderFactoryFunc. * * \sa unregisterAppender(), registeredAppenders(), createAppender() */ static void registerAppender(const QString &rAppenderClassName, AppenderFactoryFunc pAppenderFactoryFunc); /*! * This is an overloaded member function, provided for convenience. */ static void registerAppender(const char *pAppenderClassName, AppenderFactoryFunc pAppenderFactoryFunc); /*! * Registers the Filter factory function \a pFilterFactoryFunc * for the class \a rFilterClassName. If a registered factory * function exists for the class, it is replaced with * \a pFilterFactoryFunc. * * \sa unregisterFilter(), registeredFilters(), createFilter() */ static void registerFilter(const QString &rFilterClassName, FilterFactoryFunc pFilterFactoryFunc); /*! * This is an overloaded member function, provided for convenience. */ static void registerFilter(const char *pFilterClassName, FilterFactoryFunc pFilterFactoryFunc); /*! * Registers the Layout factory function \a pLayoutFactoryFunc * for the class \a rLayoutClassName. If a registered factory * function exists for the class, it is replaced with * \a pLayoutFactoryFunc. * * \sa unregisterLayout(), registeredLayout(), createLayout() */ static void registerLayout(const QString &rLayoutClassName, LayoutFactoryFunc pLayoutFactoryFunc); /*! * This is an overloaded member function, provided for convenience. */ static void registerLayout(const char *pLayoutClassName, LayoutFactoryFunc pLayoutFactoryFunc); /*! * Returns a list of the class names for registered Appender factory * functions. * * \sa registerAppender(), unregisterAppender() */ static QStringList registeredAppenders(); /*! * Returns a list of the class names for registered Filter factory * functions. * * \sa registerFilter(), unregisterFilter() */ static QStringList registeredFilters(); /*! * Returns a list of the class names for registered Layout factory * functions. * * \sa registerLayout(), unregisterLayout() */ static QStringList registeredLayouts(); /*! * Sets the property \a rProperty of the object \a pObject to the * value \a rValue. The function will test that the property * \a rProperty is writeable and of a type the function can convert to. * The types bool, int, Level and QString are supported. * * \sa OptionConverter */ static void setObjectProperty(QObject *pObject, const QString &rProperty, const QString &rValue); /*! * This is an overloaded member function, provided for convenience. */ static void setObjectProperty(QObject *pObject, const char *pProperty, const QString &rValue); /*! * Unregisters the Appender factory function for the class * \a rAppenderClassName. * * \sa registerAppender(), registeredAppenders() */ static void unregisterAppender(const QString &rAppenderClassName); /*! * This is an overloaded member function, provided for convenience. */ static void unregisterAppender(const char *pAppenderClassName); /*! * Unregisters the Filter factory function for the class * \a rFilterClassName. * * \sa registerFilter(), registeredFilters() */ static void unregisterFilter(const QString &rFilterClassName); /*! * This is an overloaded member function, provided for convenience. */ static void unregisterFilter(const char *pFilterClassName); /*! * Unregisters the Layout factory function for the class * \a rLayoutClassName. * * \sa registerLayout(), registeredLayouts() */ static void unregisterLayout(const QString &rLayoutClassName); /*! * This is an overloaded member function, provided for convenience. */ static void unregisterLayout(const char *pLayoutClassName); private: Appender *doCreateAppender(const QString &rAppenderClassName); Filter *doCreateFilter(const QString &rFilterClassName); Layout *doCreateLayout(const QString &rLayoutClassName); void doRegisterAppender(const QString &rAppenderClassName, AppenderFactoryFunc pAppenderFactoryFunc); void doRegisterFilter(const QString &rFilterClassName, FilterFactoryFunc pFilterFactoryFunc); void doRegisterLayout(const QString &rLayoutClassName, LayoutFactoryFunc pLayoutFactoryFunc); void doSetObjectProperty(QObject *pObject, const QString &rProperty, const QString &rValue); void doUnregisterAppender(const QString &rAppenderClassName); void doUnregisterFilter(const QString &rFilterClassName); void doUnregisterLayout(const QString &rLayoutClassName); void registerDefaultAppenders(); void registerDefaultFilters(); void registerDefaultLayouts(); bool validateObjectProperty(QMetaProperty &rMetaProperty, const QString &rProperty, QObject *pObject); private: mutable QMutex mObjectGuard; QHash mAppenderRegistry; QHash mFilterRegistry; QHash mLayoutRegistry; }; /************************************************************************** * Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM /*! * \relates Factory * * Writes all object member variables to the given debug stream \a rDebug and * returns the stream. * * * %Factory(appenderfactories:("Log4Qt::DebugAppender", "Log4Qt::NullAppender", * "Log4Qt::ConsoleAppender", "org.apache.log4j.varia.DebugAppender", * "org.apache.log4j.FileAppender", "org.apache.log4j.RollingFileAppender", * "org.apache.log4j.DailyRollingFileAppender", * "org.apache.log4j.varia.ListAppender", * "org.apache.log4j.varia.NullAppender", * "Log4Qt::FileAppender", "org.apache.log4j.ConsoleAppender", * "Log4Qt::DailyRollingFileAppender", "Log4Qt::ListAppender", * "Log4Qt::RollingFileAppender") filterfactories: * ("Log4Qt::DenyAllFilter", "Log4Qt::StringMatchFilter", * "Log4Qt::LevelRangeFilter", "org.apache.log4j.varia.DenyAllFilter", * "org.apache.log4j.varia.LevelRangeFilter", * "org.apache.log4j.varia.StringMatchFilter", "Log4Qt::LevelMatchFilter", * "org.apache.log4j.varia.LevelMatchFilter") layoutfactories: * ("org.apache.log4j.SimpleLayout", "Log4Qt::PatternLayout", * "Log4Qt::SimpleLayout", "org.apache.log4j.TTCCLayout", * "Log4Qt::TTCCLayout", "org.apache.log4j.PatternLayout") ) * * \sa QDebug, Factory::logManager() */ QDebug operator<<(QDebug debug, const Factory &rFactory); #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Inline **************************************************************************/ inline Appender *Factory::createAppender(const QString &rAppenderClassName) { return instance()->doCreateAppender(rAppenderClassName); } inline Appender *Factory::createAppender(const char *pAppenderClassName) { return instance()->doCreateAppender(QLatin1String(pAppenderClassName)); } inline Filter *Factory::createFilter(const QString &rFilterClassName) { return instance()->doCreateFilter(rFilterClassName); } inline Filter *Factory::createFilter(const char *pFilterClassName) { return instance()->doCreateFilter(QLatin1String(pFilterClassName)); } inline Layout *Factory::createLayout(const QString &rLayoutClassName) { return instance()->doCreateLayout(rLayoutClassName); } inline Layout *Factory::createLayout(const char *pLayoutClassName) { return instance()->doCreateLayout(QLatin1String(pLayoutClassName)); } inline void Factory::registerAppender(const QString &rAppenderClassName, AppenderFactoryFunc pAppenderFactoryFunc) { instance()->doRegisterAppender(rAppenderClassName, pAppenderFactoryFunc); } inline void Factory::registerAppender(const char *pAppenderClassName, AppenderFactoryFunc pAppenderFactoryFunc) { instance()->doRegisterAppender(QLatin1String(pAppenderClassName), pAppenderFactoryFunc); } inline void Factory::registerFilter(const QString &rFilterClassName, FilterFactoryFunc pFilterFactoryFunc) { instance()->doRegisterFilter(rFilterClassName, pFilterFactoryFunc); } inline void Factory::registerFilter(const char *pFilterClassName, FilterFactoryFunc pFilterFactoryFunc) { instance()->doRegisterFilter(QLatin1String(pFilterClassName), pFilterFactoryFunc); } inline void Factory::registerLayout(const QString &rLayoutClassName, LayoutFactoryFunc pLayoutFactoryFunc) { instance()->doRegisterLayout(rLayoutClassName, pLayoutFactoryFunc); } inline void Factory::registerLayout(const char *pLayoutClassName, LayoutFactoryFunc pLayoutFactoryFunc) { instance()->doRegisterLayout(QLatin1String(pLayoutClassName), pLayoutFactoryFunc); } inline QStringList Factory::registeredAppenders() { QMutexLocker locker(&instance()->mObjectGuard); return instance()->mAppenderRegistry.keys(); } inline QStringList Factory::registeredFilters() { QMutexLocker locker(&instance()->mObjectGuard); return instance()->mFilterRegistry.keys(); } inline QStringList Factory::registeredLayouts() { QMutexLocker locker(&instance()->mObjectGuard); return instance()->mLayoutRegistry.keys(); } inline void Factory::setObjectProperty(QObject *pObject, const QString &rProperty, const QString &rValue) { instance()->doSetObjectProperty(pObject, rProperty, rValue); } inline void Factory::setObjectProperty(QObject *pObject, const char *pProperty, const QString &rValue) { instance()->doSetObjectProperty(pObject, QLatin1String(pProperty), rValue); } inline void Factory::unregisterAppender(const QString &rAppenderClassName) { instance()->doUnregisterAppender(rAppenderClassName); } inline void Factory::unregisterAppender(const char *pAppenderClassName) { instance()->doUnregisterAppender(QLatin1String(pAppenderClassName)); } inline void Factory::unregisterFilter(const QString &rFilterClassName) { instance()->doUnregisterFilter(rFilterClassName); } inline void Factory::unregisterFilter(const char *pFilterClassName) { instance()->doUnregisterFilter(QLatin1String(pFilterClassName)); } inline void Factory::unregisterLayout(const QString &rLayoutClassName) { instance()->doUnregisterLayout(rLayoutClassName); } inline void Factory::unregisterLayout(const char *pLayoutClassName) { instance()->doUnregisterLayout(QLatin1String(pLayoutClassName)); } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::Factory, Q_COMPLEX_TYPE); // use default #endif // LOG4QT_HELPERS_FACTORY_H ukui-interface/src/log4qt/log4qt/helpers/logobject.cpp0000664000175000017500000000410115167726064021756 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: logobject.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/helpers/logobject.h" #include namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: LogObject **************************************************************************/ /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const LogObject &rLogObject) { return rLogObject.debug(debug); } #endif // QT_NO_DEBUG_STREAM } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/helpers/datetime.h0000664000175000017500000001740615167726076021266 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: datetime.h * created: September 2007 * author: Martin Heinrich * * * changes: Sep 2008, Martin Heinrich: * - Resolved compilation problem with Microsoft Visual Studio 2005 * * * Copyright 2007 - 2008 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_HELPERS_DATETIME_H #define LOG4QT_HELPERS_DATETIME_H /****************************************************************************** * Dependencies ******************************************************************************/ #include #include #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ namespace Log4Qt { /*! * \brief The class DateTime provides extended functionality for QDateTime. * * The class DateTime implements additional formatting options for * toString() and provides conversion functions from and to milliseconds. */ class LIBUKUILOG4QT_EXPORT DateTime : public QDateTime { public: /*! * Constructs a null date time. * * \sa QDateTime::QDateTime() */ DateTime(); // DateTime(const DateTime &rOther); // Use compiler default /*! * Constructs a copy of another QDateTime. * * \sa QDateTime::QDateTime(const QDateTime &rOther) */ DateTime(const QDateTime &rOther); #if QT_VERSION < 0x060500 /*! * Constructs a datetime with the given \a date and \a time, using * the time specification defined by \a timeSpec. * * \sa QDateTime::QDateTime(const QDate &date, const QTime &time, * Qt::TimeSpec timeSpec = Qt::LocalTime) */ DateTime(QDate date, QTime time, Qt::TimeSpec timeSpec = Qt::LocalTime); #else /*! * Constructs a datetime with the given \a date and \a time, using * the time zone defined by \a QTimeZone. * * \sa QDateTime::QDateTime(const QDate &date, const QTime &time, * QTimeZone = QTimeZone(QTimeZone::LocalTime)) */ DateTime(QDate date, QTime time, QTimeZone = QTimeZone(QTimeZone::LocalTime)); #endif // virtual ~DateTime(); // Use compiler default /*! * Assigns \a rOther to this DateTime and returns a reference to it. */ DateTime &operator=(const DateTime &rOther); /*! * Returns the datetime as the number of milliseconds that have passed * since 1970-01-01T00:00:00,000, Coordinated Universal Time (Qt::UTC). * * \sa QDateTime::toTime_t() */ qint64 toMilliSeconds() const; /*! * Returns the datetime as a string. The \a rFormat parameter * determines the format of the result string. * * In addition to the expressions of QDateTime::toString(const QString * &rFormat) the following expression can be used. * * * * * * * * * * * * *
Expression Output
w the week of the year as number without a leading zero (1 to 53)
ww the week of the year as number with a leading zero (01 to 53)
* * Alternatively the \a rFormat parameter can specify one of the * following strings. * * * * * * * * * * * * * * * * * * * * * *
String Format
TIME_ABSOLUTE uses the format HH:mm:ss.zzz
DATE uses the format dd MMM YYYY HH:mm:ss.zzzz
ISO8601 uses the format yyyy-MM-dd hh:mm:ss.zzz
NONE uses an empty string as format
TIME_RELATIVE returns the milliseconds since start of the program
* * \sa QDateTime::toString(const QString &rFormat) */ QString toString(const QString &rFormat) const; /*! * Returns the current datetime, as reported by the system clock, in * the local time zone. * * \sa QDateTime::currentDateTime() */ static DateTime currentDateTime(); /*! * Returns a datetime whose date and time are the number of * milliseconds that have passed since 1970-01-01T00:00:00, * Coordinated Universal Time (Qt::UTC). * * \sa QDateTime::fromTime_t(uint seconds) */ static DateTime fromMilliSeconds(qint64 milliSeconds); private: QString formatDateTime(const QString &rFormat) const; QString formatToken(const QString &rToken, bool am_pm) const; static bool hasAMPM(const QString &rFormat); }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline DateTime::DateTime() : QDateTime() {} inline DateTime::DateTime(const QDateTime &rOther) : QDateTime(rOther) {} #if QT_VERSION < 0x060500 inline DateTime::DateTime(QDate date, QTime time, Qt::TimeSpec timeSpec) : QDateTime(date, time, timeSpec) {} #else inline DateTime::DateTime(QDate date, QTime time, QTimeZone timeZone) : QDateTime(date, time, timeZone) {} #endif inline DateTime &DateTime::operator=(const DateTime &rOther) { QDateTime::operator=(rOther); return *this; } #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) inline qint64 DateTime::toMilliSeconds() const { return (qint64)1000 * toTime_t() + time().msec(); } #else inline qint64 DateTime::toMilliSeconds() const { return toMSecsSinceEpoch(); } #endif inline DateTime DateTime::currentDateTime() { return DateTime(QDateTime::currentDateTime()); } #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) inline DateTime DateTime::fromMilliSeconds(qint64 milliSeconds) { return DateTime(QDateTime::fromTime_t(milliSeconds / 1000).addMSecs(milliSeconds % 1000)); } #else inline DateTime DateTime::fromMilliSeconds(qint64 milliSeconds) { return DateTime(QDateTime::fromSecsSinceEpoch(milliSeconds / 1000).addMSecs(milliSeconds % 1000)); } #endif } // namespace Log4Qt Q_DECLARE_TYPEINFO(Log4Qt::DateTime, Q_MOVABLE_TYPE); #endif // LOG4QT_HELPERS_DATETIME_H ukui-interface/src/log4qt/log4qt/helpers/optionconverter.h0000664000175000017500000001337315167726076022731 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: optionconverter.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_OPTIONCONVERTER_H #define LOG4QT_OPTIONCONVERTER_H #include "ukui-logmacros.h" /****************************************************************************** * Dependencies ******************************************************************************/ #include #include "log4qt/level.h" namespace Log4Qt { class Properties; /*! * \brief The class OptionConverter provides functions to convert strings * to property values. */ class LIBUKUILOG4QT_EXPORT OptionConverter { private: OptionConverter(); OptionConverter(const OptionConverter &rOther); // Not implemented // virtual ~OptionConverter(); // Use compiler default OptionConverter &operator=(const OptionConverter &rOther); // Not implemented public: static QString findAndSubst(const Properties &rProperties, const QString &rKey); /*! * Returns the JAVA class name \a rClassName as C++ class name by * replacing all . characters with ::. */ static QString classNameJavaToCpp(const QString &rClassName); /*! * Converts the option \a rOption to a boolean value. Valid strings * for true are "true", "enabled" and "1". Valid strings * for false are "false", "disabled" and "0". If the conversion is * successful, the target is returned and \a p_ok is set to true. * Otherwise an error is written to the log, \a p_ok is set to false * and false is returned. */ static bool toBoolean(const QString &rOption, bool *p_ok = 0); static bool toBoolean(const QString &rOption, bool default_value); /*! * Converts the option string \a rOption to a file size. The string can * be a positive integer followed by an optional unit suffix "KB", "MB" * or "GB". If a unit suffix is specified the the integer is * interpreted as kilobytes, megabytes or gigabytes. If the conversion * is successful, the size is returned and \a p_ok is set to true. * Otherwise an error is written to the log, \a p_ok is set to false * and 0 is returned. */ static qint64 toFileSize(const QString &rOption, bool *p_ok = 0); /*! * Converts the option \a rOption to a integer value using * QString::toInt(). If the conversion is successful, the integer is * returned and \a p_ok is set to true. Otherwise an error is written * to the log, \a p_ok is set to false and 0 is returned. */ static int toInt(const QString &rOption, bool *p_ok = 0); /*! * Converts the option \a rOption to a qint64 value using * QString::toLongLong(). If the conversion is successful, the qint64 is * returned and \a p_ok is set to true. Otherwise an error is written * to the log, \a p_ok is set to false and 0 is returned. */ static qint64 toQInt64(const QString &rOption, bool *p_ok = 0); /*! * Converts the option \a rOption to a level value using * Level::fromString(). If the conversion is successful, the level * is returned and \a p_ok is set to true. Otherwise an error is * written to the log, \a p_ok is set to false and a level with * the value Level::NULL_INT is returned. * * \sa Level::fromString() */ static Level toLevel(const QString &rOption, bool *p_ok = 0); static Level toLevel(const QString &rOption, const Level &rDefaultValue); /*! * Converts the option \a rOption to a ConsoleAppender::Target value. * Valid strings for \a rOption are "System.out", "STDOUT_TARGET", * "System.err" and "STDERR_TARGET". If the conversion is successful, * the target is returned and \a p_ok is set to true. Otherwise an * error is written to the log, \a p_ok is set to false and * ConsoleAppender::STDOUT_TARGET is returned. */ static int toTarget(const QString &rOption, bool *p_ok = 0); }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ } // namespace Log4Qt Q_DECLARE_TYPEINFO(Log4Qt::OptionConverter, Q_COMPLEX_TYPE); #endif // LOG4QT_OPTIONCONVERTER_H ukui-interface/src/log4qt/log4qt/helpers/datetime.cpp0000664000175000017500000002355515167726076021623 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: datetime.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/helpers/datetime.h" #include #include #include "log4qt/helpers/initialisationhelper.h" namespace Log4Qt { /************************************************************************** *Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: DateTime **************************************************************************/ QString DateTime::toString(const QString &rFormat) const { QString format(rFormat); if (format.isEmpty()) return QString(); if (!isValid()) return QString(); if (format == QLatin1String("NONE")) return QString(); if (format == QLatin1String("TIME_RELATIVE")) return QString::number(toMilliSeconds() - InitialisationHelper::startTime()); if (format == QLatin1String("ISO8601")) format = QLatin1String("yyyy-MM-dd hh:mm:ss.zzz"); if (format == QLatin1String("TIME_ABSOLUTE")) format = QLatin1String("HH:mm:ss.zzz"); if (format == QLatin1String("DATE")) format = QLatin1String("dd MMM YYYY HH:mm:ss.zzzz"); return formatDateTime(format); } QString DateTime::formatDateTime(const QString &rFormat) const { if (rFormat.isEmpty()) return QString(); if (!isValid()) return QString(); const QLatin1Char null('0'); const QLatin1Char quote('\''); const QString tokens = QLatin1String("\'dMyhHmszAPapw"); const bool am_pm = hasAMPM(rFormat); QString result; QString token; QChar expected = null; QChar c; int i; for (i = 0; i < rFormat.length(); i++) { c = rFormat.at(i); // Handle literal text if (expected == quote) { if (c == quote) { Q_ASSERT_X(i > 0, "DateTime::toString()", "Found quote with status quote at i = 0"); if (i > 0 && rFormat.at(i - 1) == quote) // Second of two quotes result += quote; expected = null; } else // Next literal character result += c; } else if (c == expected) { // Extend token token += c; } else { // Close last token result += formatToken(token, am_pm); token.clear(); expected = null; // Test for valid character if (tokens.indexOf(c) >= 0) { if (c == QLatin1Char('a')) expected = QLatin1Char('p'); else if (c == QLatin1Char('A')) expected = QLatin1Char('P'); else if (c.toLower() == QLatin1Char('p')) expected = null; else expected = c; if (c != quote) token += c; } else result += c; } } result += formatToken(token, am_pm); return QString(result); } QString DateTime::formatToken(const QString &rToken, bool am_pm) const { if (rToken.isEmpty()) return QString(); const QChar c = rToken.at(0); QString result; QLocale locale; int used = 0; // Qt data format strings if (rToken.startsWith(QLatin1String("dddd"))) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) result = QDate::longDayName(date().dayOfWeek()); #else result = locale.standaloneDayName(date().dayOfWeek(), QLocale::LongFormat); #endif used = 4; } else if (rToken.startsWith(QLatin1String("ddd"))) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) result = QDate::shortDayName(date().dayOfWeek()); #else result = locale.standaloneDayName(date().dayOfWeek(), QLocale::ShortFormat); #endif used = 3; } else if (rToken.startsWith(QLatin1String("dd"))) { result = QString::number(date().day()).rightJustified(2, QLatin1Char('0'), true); used = 2; } else if (c == QLatin1Char('d')) { result = QString::number(date().day()); used = 1; } else if (rToken.startsWith(QLatin1String("MMMM"))) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) result = QDate::longMonthName(date().month()); #else locale.standaloneMonthName(date().month(), QLocale::LongFormat); #endif used = 4; } else if (rToken.startsWith(QLatin1String("MMM"))) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) result = QDate::shortMonthName(date().month()); #else locale.standaloneMonthName(date().month(), QLocale::ShortFormat); #endif used = 3; } else if (rToken.startsWith(QLatin1String("MM"))) { result = QString::number(date().month()).rightJustified(2, QLatin1Char('0'), true); used = 2; } else if (c == QLatin1Char('M')) { result = QString::number(date().month()); used = 1; } else if (rToken.startsWith(QLatin1String("yyyy"))) { result = QString::number(date().year()); used = 4; } else if (rToken.startsWith(QLatin1String("yy"))) { result = QString::number(date().year() % 100).rightJustified(2, QLatin1Char('0'), true); used = 2; } // Qt time format strings else if (rToken.startsWith(QLatin1String("hh")) || rToken.startsWith(QLatin1String("HH"))) { int hour = time().hour(); if (am_pm && c == QLatin1Char('h') && hour > 12) hour -= 12; result = QString::number(hour).rightJustified(2, QLatin1Char('0'), true); used = 2; } else if (c == QLatin1Char('h') || c == QLatin1Char('H')) { int hour = time().hour(); if (am_pm && c == QLatin1Char('h') && hour > 12) hour -= 12; result = QString::number(hour); used = 2; } else if (rToken.startsWith(QLatin1String("mm"))) { result = QString::number(time().minute()).rightJustified(2, QLatin1Char('0'), true); used = 2; } else if (c == (QLatin1Char('m'))) { result = QString::number(time().minute()); used = 1; } else if (rToken.startsWith(QLatin1String("ss"))) { result = QString::number(time().second()).rightJustified(2, QLatin1Char('0'), true); used = 2; } else if (c == QLatin1Char('s')) { result = QString::number(time().second()); used = 1; } else if (rToken.startsWith(QLatin1String("zzz"))) { result = QString::number(time().msec()).rightJustified(3, QLatin1Char('0'), true); used = 3; } else if (c == QLatin1Char('z')) { result = QString::number(time().msec()); used = 1; } else if (c.toLower() == QLatin1Char('a')) { bool is_lower = c == QLatin1Char('a'); if (time().hour() < 12) result = QLatin1String("AM"); else result = QLatin1String("PM"); if (is_lower) result = result.toLower(); if (rToken.size() > 1 && ((is_lower && rToken.at(1) == QLatin1Char('p')) || (!is_lower && rToken.at(1) == QLatin1Char('P'))) ) used = 2; else used = 1; } // Extension for week number else if (rToken.startsWith(QLatin1String("ww"))) { result = QString::number(date().weekNumber()).rightJustified(2, QLatin1Char('0'), true); used = 2; } else if (c == QLatin1Char('w')) { result = QString::number(date().weekNumber()); used = 1; } if (used) return result + formatToken(rToken.mid(used), am_pm); else return QString(result); } bool DateTime::hasAMPM(const QString &rToken) { bool in_literal = false; QChar c; int i; for (i = 0; i < rToken.length(); i++) { c = rToken.at(i); if (c == QLatin1Char('\'')) in_literal = !in_literal; else if (!in_literal && c.toLower() == QLatin1Char('a')) return true; } return false; } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/fileappender.h0000664000175000017500000001657615167726064020472 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: fileappender.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_FILEAPPENDER_H #define LOG4QT_FILEAPPENDER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/writerappender.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ class QFile; class QTextStream; namespace Log4Qt { /*! * \brief The class FileAppender appends log events to a file. * * \note All the functions declared in this class are thread-safe. * * \note The ownership and lifetime of objects of this class are managed. See * \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT FileAppender : public WriterAppender { Q_OBJECT /*! * The property holds, if the output is appended to the file. * * The default is false for not appending. * * \sa appendFile(), setAppendFile() */ Q_PROPERTY(bool appendFile READ appendFile WRITE setAppendFile) /*! * The property holds, if the output is buffered. * * The default is true for buffering. * * \sa bufferedIo(), setBufferedIo() */ Q_PROPERTY(bool bufferedIo READ bufferedIo WRITE setBufferedIo) /*! * The property holds the name of the file. * * \sa file(), setFile() */ Q_PROPERTY(QString file READ file WRITE setFile) public: FileAppender(QObject *pParent = 0); FileAppender(Layout *pLayout, const QString &rFileName, QObject *pParent = 0); FileAppender(Layout *pLayout, const QString &rFileName, bool append, QObject *pParent = 0); FileAppender(Layout *pLayout, const QString &rFileName, bool append, bool buffered, QObject *pParent = 0); virtual ~FileAppender(); private: FileAppender(const FileAppender &rOther); // Not implemented FileAppender &operator=(const FileAppender &rOther); // Not implemented public: bool appendFile() const; QString file() const; bool bufferedIo() const; // JAVA: int bufferSize() const; void setAppendFile(bool append); void setBufferedIo(bool buffered); // JAVA: void setBufferSize(int bufferSize); void setFile(const QString &rFileName); virtual void activateOptions(); virtual void close(); protected: /*! * Tests if all entry conditions for using append() in this class are met. * * If a conditions is not met, an error is logged and the function returns * false. Otherwise the result of WriterAppender::checkEntryConditions() * is returned. * * The checked conditions are: * - That a file is set and open (APPENDER_NO_OPEN_FILE_ERROR) * * The function is called as part of the checkEntryConditions() chain * started by AppenderSkeleton::doAppend(). * * \sa AppenderSkeleton::doAppend(), AppenderSkeleton::checkEntryConditions() */ virtual bool checkEntryConditions() const; void closeFile(); #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream \a rDebug * and returns the stream. * * * %FileAppender(name:"FA" appendfile:false bufferedio:true encoding:"" * file:"/log.txt" filter: 0x0 immediateflush:true isactive:false * isclosed:false layout:"TTCC" referencecount:2 * threshold:"NULL" writer:0x0) * * \sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const; #endif // QT_NO_DEBUG_STREAM /*! * Checks for file I/O errrors. If an error is found it is logged and the * function returns true. Otherwise false is returned. */ virtual bool handleIoErrors() const; /*! * Opens the file for the appender based on the specified file name and * mode. A text stream is created and passed on to the super class * WriterAppender. * * If the parent directory of the specified file does not exists, * it is created. */ void openFile(); /*! * Removes the file \a rFile. If the operation is successful, true is * returned. Otherwise an APPENDER_REMOVE_FILE_ERROR error is logged * and false is returned. */ bool removeFile(QFile &rFile) const; /*! * Renames the file \a rFile to \a rFileName. If the operation is * successful, true is returned. Otherwise an * APPENDER_RENAMING_FILE_ERROR error is logged and false is returned. */ bool renameFile(QFile &rFile, const QString &rFileName) const; // JAVA: void setQWForFiles(Writer writer); private: volatile bool mAppendFile; volatile bool mBufferedIo; QString mFileName; QFile *mpFile; QTextStream *mpTextStream; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline bool FileAppender::appendFile() const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe return mAppendFile; } inline QString FileAppender::file() const { QMutexLocker locker(&mObjectGuard); return mFileName; } inline bool FileAppender::bufferedIo() const { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe return mBufferedIo; } inline void FileAppender::setAppendFile(bool append) { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe mAppendFile = append; } inline void FileAppender::setBufferedIo(bool buffered) { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe mBufferedIo = buffered; } inline void FileAppender::setFile(const QString &rFileName) { QMutexLocker locker(&mObjectGuard); mFileName = rFileName; } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::FileAppender, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_FILEAPPENDER_H ukui-interface/src/log4qt/log4qt/consoleappender.h0000664000175000017500000001146215167726064021202 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: consoleappender.h * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #ifndef LOG4QT_CONSOLEAPPENDER_H #define LOG4QT_CONSOLEAPPENDER_H /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/writerappender.h" #include "ukui-logmacros.h" /****************************************************************************** * Declarations ******************************************************************************/ class QFile; class QTextStream; namespace Log4Qt { /*! * \brief The class ConsoleAppender appends to stdout or stderr. * * \note All the functions declared in this class are thread-safe. * * \note The ownership and lifetime of objects of this class are managed. * See \ref Ownership "Object ownership" for more details. */ class LIBUKUILOG4QT_EXPORT ConsoleAppender : public WriterAppender { Q_OBJECT /*! * The property holds the target used by the appender. * * The default is STDOUT_TARGET for the standard output. * * \sa Target, target(), setTarget() */ Q_PROPERTY(QString target READ target WRITE setTarget) public: /*! * The enum defines the possible output targets * * \sa target(), setTarget() */ enum Target { /*! The output target is standard out. */ STDOUT_TARGET, /*! The output target is standard error. */ STDERR_TARGET }; Q_ENUMS(Target) ConsoleAppender(QObject *pParent = 0); ConsoleAppender(Layout *pLayout, QObject *pParent = 0); ConsoleAppender(Layout *pLayout, const QString &rTarget, QObject *pParent = 0); /*! * Creates a ConsoleAppender with the layout \a pLayout, the target * value specified by the \a target constant and the parent * \a pParent. */ ConsoleAppender(Layout *pLayout, Target target, QObject *pParent = 0); virtual ~ConsoleAppender(); private: ConsoleAppender(const ConsoleAppender &rOther); // Not implemented ConsoleAppender &operator=(const ConsoleAppender &rOther); // Not implemented public: // JAVA: bool follow() const; QString target() const; // JAVA: void setFollow(bool follow); void setTarget(const QString &rTarget); /*! * Sets the target to the value specified by the \a target constant. */ void setTarget(Target target); virtual void activateOptions(); virtual void close(); protected: void closeStream(); #ifndef QT_NO_DEBUG_STREAM /*! * Writes all object member variables to the given debug stream * \a rDebug and returns the stream. * * * %ConsoleAppender(name:"CA" filter:0x0 isactive:true isclosed:false * layout:"PL" target:"STDERR" referenceCount:1 * threshold:"WARN_SET") * * \sa QDebug, operator<<(QDebug debug, const LogObject &rLogObject) */ virtual QDebug debug(QDebug &rDebug) const; #endif // QT_NO_DEBUG_STREAM private: volatile Target mTarget; QTextStream *mpTextStream; }; /************************************************************************** * Operators, Helper **************************************************************************/ /************************************************************************** * Inline **************************************************************************/ inline void ConsoleAppender::setTarget(Target target) { // QMutexLocker locker(&mObjectGuard); // Read/Write of int is safe mTarget = target; } } // namespace Log4Qt // Q_DECLARE_TYPEINFO(Log4Qt::ConsoleAppender, Q_COMPLEX_TYPE); // Use default #endif // LOG4QT_CONSOLEAPPENDER_H ukui-interface/src/log4qt/log4qt/simplelayout.cpp0000664000175000017500000000460415167726064021103 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: simplelayout.cpp * created: September 2007 * author: Martin Heinrich * * * Copyright 2007 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/simplelayout.h" #include #include "log4qt/loggingevent.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: SimpleLayout **************************************************************************/ QString SimpleLayout::format(const LoggingEvent &rEvent) { return rEvent.level().toString() + QLatin1String(" - ") + rEvent.message() + Layout::endOfLine(); } #ifndef QT_NO_DEBUG_STREAM QDebug SimpleLayout::debug(QDebug &rDebug) const { rDebug.nospace() << "SimpleLayout(" << "name:" << name() << " " << "referencecount:" << referenceCount() << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ } // namespace Log4Qt ukui-interface/src/log4qt/log4qt/logger.cpp0000664000175000017500000002157415167726064017640 0ustar fengfeng/****************************************************************************** * * package: Log4Qt * file: logger.cpp * created: September 2007 * author: Martin Heinrich * * * changes: Sep 2008, Martin Heinrich: * - Fixed problem in Qt 4.4 where QReadWriteLock is by default * non-recursive. * * * Copyright 2007 - 2008 Martin Heinrich * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ /****************************************************************************** * Dependencies ******************************************************************************/ #include "log4qt/logger.h" #include #include "log4qt/appenderskeleton.h" #include "log4qt/varia/listappender.h" #include "log4qt/loggingevent.h" #include "log4qt/log4qt.h" #include "log4qt/loggerrepository.h" #include "log4qt/logmanager.h" namespace Log4Qt { /************************************************************************** * Declarations **************************************************************************/ /************************************************************************** * C helper functions **************************************************************************/ /************************************************************************** * Class implementation: Logger **************************************************************************/ Logger::Logger(LoggerRepository* pLoggerRepository, Level level, const QString &rName, Logger *pParent) : QObject(0), #if QT_VERSION < QT_VERSION_CHECK(4, 4, 0) mObjectGuard(), #else mObjectGuard(QReadWriteLock::Recursive), #endif mName(rName), mpLoggerRepository(pLoggerRepository), mAdditivity(true), mAppenders(), mLevel(level), mpParent(pParent) { Q_ASSERT_X(pLoggerRepository, "Logger::Logger()", "Construction of Logger with null LoggerRepository"); setObjectName(mName); } Logger::~Logger() { logger()->warn("Unexpected destruction of Logger"); // QWriteLocker locker(&mObjectGuard); // // QMutableListIterator< LogObjectPtr > i(mAppenders); // while (i.hasNext()) // { // i.next(); // i.remove(); // } } QList Logger::appenders() const { QReadLocker locker(&mObjectGuard); QList result; Appender *p_appender; Q_FOREACH(p_appender, mAppenders) result << p_appender; return result; } void Logger::setLevel(Level level) { // QWriteLocker locker(&mObjectGuard); // Read/Write int is safe if ((parentLogger() == 0) && (level == Level::NULL_INT)) { logger()->warn("Invalid root logger level NULL_INT. Using DEBUG_INT instead"); level = Level::DEBUG_INT; } mLevel = level; } void Logger::addAppender(Appender *pAppender) { // Avoid deadlock: // - Handle warnings, before write lock is aquired // Keep objects with a 0 reference count safe LogObjectPtr p_appender = pAppender; { QReadLocker locker(&mObjectGuard); if(!p_appender) { logger()->warn("Adding null Appender to Logger '%1'", name()); return; } if(mAppenders.contains(p_appender)) { logger()->warn("Adding of duplicate appender '%2' to logger '%1'", name(), p_appender->name()); return; } } { QWriteLocker locker(&mObjectGuard); if(mAppenders.contains(p_appender)) return; mAppenders.append(p_appender); } } Appender *Logger::appender(const QString &rName) const { QReadLocker locker(&mObjectGuard); Appender *p_appender; Q_FOREACH(p_appender, mAppenders) if (p_appender->name() == rName) return p_appender; return 0; } void Logger::callAppenders(const LoggingEvent &rEvent) const { QReadLocker locker(&mObjectGuard); Appender *p_appender; Q_FOREACH(p_appender, mAppenders) p_appender->doAppend(rEvent); if (additivity() && (parentLogger() != 0)) parentLogger()->callAppenders(rEvent); } bool Logger::isAttached(Appender *pAppender) const { QReadLocker locker(&mObjectGuard); // Keep objects with a 0 reference count safe LogObjectPtr p_appender = pAppender; return mAppenders.contains(p_appender); } void Logger::removeAllAppenders() { // Avoid deadlock: // - Only log warnings without having the write log aquired // - Hold a reference to all appenders so that the remove does not // destruct the appender over the reference count while the write // log is held. The appender may log messages. logger()->trace("Removing all appenders from logger '%1'", name()); QList< LogObjectPtr > appenders; { QWriteLocker locker(&mObjectGuard); QMutableListIterator< LogObjectPtr > i(mAppenders); while (i.hasNext()) { Appender *p_appender = i.next(); ListAppender *p_listappender = qobject_cast(p_appender); if (p_listappender && p_listappender->configuratorList()) continue; else { appenders << p_appender; i.remove(); } } } appenders.clear(); } void Logger::removeAppender(Appender *pAppender) { // Avoid deadlock: // - Only log warnings without having the write log aquired // - Hold a reference to the appender so that the remove does not // destruct the appender over the reference count while the write // log is held. The appender may log messages. LogObjectPtr p_appender = pAppender; if(!p_appender) { logger()->warn("Request to remove null Appender from Logger '%1'", name()); return; } int n; { QWriteLocker locker(&mObjectGuard); n = mAppenders.removeAll(p_appender); } if (n == 0) { logger()->warn("Request to remove Appender '%2', which is not part of Logger '%1' appenders", name(), p_appender->name()); return; } } void Logger::removeAppender(const QString &rName) { Appender *p_appender = appender(rName); if (p_appender) removeAppender(p_appender); } Level Logger::effectiveLevel() const { Q_ASSERT_X(LogManager::rootLogger()->level() != Level::NULL_INT, "Logger::effectiveLevel()", "Root logger level must not be NULL_INT"); QReadLocker locker(&mObjectGuard); const Logger *p_logger = this; while (p_logger->level() == Level::NULL_INT) p_logger = p_logger->parentLogger(); return p_logger->level(); } bool Logger::isEnabledFor(Level level) const { if (mpLoggerRepository->isDisabled(level)) return false; return (effectiveLevel() <= level); } Logger *Logger::logger(const QString &rName) { return LogManager::logger(rName); } Logger *Logger::logger(const char *pName) { return LogManager::logger(QLatin1String(pName)); } Logger *Logger::rootLogger() { return LogManager::rootLogger(); } #ifndef QT_NO_DEBUG_STREAM QDebug Logger::debug(QDebug &rDebug) const { QReadLocker locker(&mObjectGuard); QString parent_logger; if (mpParent) parent_logger = mpParent->name(); rDebug.nospace() << "Logger(" << "name:" << name() << " " << "appenders:" << mAppenders.count() << " " << "additivity:" << mAdditivity << " " << mLevel << "parentLogger:" << parent_logger << ")"; return rDebug.space(); } #endif // QT_NO_DEBUG_STREAM void Logger::forcedLog(Level level, const QString &rMessage) const { QReadLocker locker(&mObjectGuard); LoggingEvent event(this, level, rMessage); callAppenders(event); } /************************************************************************** * Implementation: Operators, Helper **************************************************************************/ #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const Logger &rLogger) { return rLogger.debug(debug); } #endif // QT_NO_DEBUG_STREAM } // namespace Log4Qt ukui-interface/src/log4qt/ukui-logconfigurator.h0000664000175000017500000001103415167726076020764 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see #include #include #include "log4qt/helpers/properties.h" #include "ukui-logrolling.h" #include /** * @brief UKUI日志配置管理器类 * * 该类是日志SDK的对外接口类,负责管理日志系统的配置和初始化。 * 采用单例模式,提供全局统一的日志配置管理功能。 * * 主要功能: * - 初始化Log4Qt日志系统 * - 管理全局和应用程序特定的GSettings配置 * - 监听配置变化并动态更新日志设置 * - 管理日志文件清理和滚动策略 * - 提供定时检查机制防止日志文件过多或过大 */ class LIBUKUILOG4QT_EXPORT UkuiLog4qtConfig : public QObject { Q_OBJECT private: /** * @brief 析构函数 * 清理资源,停止定时器和线程 */ virtual ~UkuiLog4qtConfig(); /** * @brief 私有构造函数 * @param parent 父对象指针 * 实现单例模式,防止外部直接实例化 */ UkuiLog4qtConfig(QObject *parent = nullptr); public: /** * @brief 获取日志配置器单例实例 * @return 返回全局唯一的配置器实例引用 */ static UkuiLog4qtConfig &instance(); /** * @brief 初始化日志SDK * @param strAppName 应用程序名称,用于生成特定的日志文件路径和配置 * @return 0表示成功,-1表示路径错误,-2表示配置失败 */ int init(QString strAppName); /** * @brief 启动日志文件清理检查定时器 */ void startCleanUpCheckTimer(); /** * @brief 停止日志文件清理检查定时器 * * 停止定时器并清理相关资源,包括停止清理线程。 */ void stopCleanUpCheckTimer(); private Q_SLOTS: /** * @brief 定时器超时槽函数 * * 当清理检查定时器超时时调用,更新文件检查限制条件。 */ void onCleanUpCheckTimer(); void onLogOutput(); private: /** * @brief 初始化GSettings配置并设置监听 * @param strAppName 应用程序名称 * @param properties Log4Qt属性对象引用 */ void initSettings(QString strAppName, Log4Qt::Properties &properties); /** * @brief 获取日志文件列表 * @return 返回当前日志目录下的所有日志文件信息列表 */ QFileInfoList getLogFiles() const; /** * @brief 检查日志目录是否有效 * @param mainDirPath 目录主路径 * @param dirName 目录名称 * @return 如果主目录存在且可读写,且子目录不存在或者存在且可读写返回true,否则返回false */ bool checkLogDirectoryValid(const QString &mainDirPath, const QString &dirName) const; public: /** * @brief 日志文件清理检查线程对象 */ UkuiLog4qtRolling *m_threadCheckFile; private: /** * @brief 初始化状态标志 */ bool m_isInited; /** * @brief 全局GSettings配置对象 */ QGSettings *m_gsLog4qtGlobal; /** * @brief 应用程序特定GSettings配置对象 */ QGSettings *m_gsLog4qtSpecial; /** * @brief Log4Qt属性配置对象 */ Log4Qt::Properties m_log4qtProperties; /** * @brief 最大允许的日志文件数量 */ unsigned m_uMaxFileCount; /** * @brief 最大允许的日志文件总大小(字节) */ quint64 m_uMaxFileSize; /** * @brief 文件检查时间间隔(秒) */ quint64 m_timeCheckFile; /** * @brief 清理检查定时器对象 */ QTimer *m_cleanUpCheckTimer = nullptr; /** * @brief 当前基础日志文件路径 */ QString m_strBaseFilePath; bool m_isConnectToLogger = false; }; #endif // __UKUI_LOGCONFIGURATOR_H__ ukui-interface/src/log4qt/ukui-logconfigurator.cpp0000664000175000017500000005763615167726076021341 0ustar fengfeng/* * Copyright (C) 2021 Tianjin KYLIN Information Technology Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see #include #include #include #include #include #include #include // 全局互斥锁,用于保护单例实例的创建 LOG4QT_GLOBAL_STATIC(QMutex, single_config) // 主进程ID,用于标识当前进程 pid_t g_MainProcPid = -1; /** * @brief 构造函数 * @param parent 父对象指针 */ UkuiLog4qtConfig::UkuiLog4qtConfig(QObject *parent) : QObject(parent) , m_threadCheckFile(nullptr) , m_isInited(false) , m_gsLog4qtGlobal(nullptr) , m_gsLog4qtSpecial(nullptr) { // 清空Log4Qt属性配置 m_log4qtProperties.clear(); // 设置默认的文件数量限制(0表示不限制) m_uMaxFileCount = 0; // 设置默认的文件大小限制(0表示不限制) m_uMaxFileSize = 0; // 设置默认的文件检查间隔为60秒 m_timeCheckFile = 60; // 记录当前进程ID g_MainProcPid = getpid(); } /** * @brief 析构函数 */ UkuiLog4qtConfig::~UkuiLog4qtConfig() { // 停止清理检查定时器和相关线程 stopCleanUpCheckTimer(); // 清理全局GSettings配置对象 if (m_gsLog4qtGlobal) { delete m_gsLog4qtGlobal; m_gsLog4qtGlobal = nullptr; } // 清理应用程序特定GSettings配置对象 if (m_gsLog4qtSpecial) { delete m_gsLog4qtSpecial; m_gsLog4qtSpecial = nullptr; } } /** * @brief 获取单例实例 * @return 返回全局唯一的配置器实例引用 */ UkuiLog4qtConfig &UkuiLog4qtConfig::instance() { QMutexLocker locker(single_config()); static UkuiLog4qtConfig mInstance; return mInstance; } /** * @brief 初始化日志SDK * @param strAppName 应用程序名称,用于生成特定的日志文件路径和配置 * @return 0表示成功,-1表示路径错误,-2表示配置失败 */ int UkuiLog4qtConfig::init(QString strAppName) { QMutexLocker locker(single_config()); // 防止重复初始化 if (m_isInited) { return true; } // 清空现有属性配置 m_log4qtProperties.clear(); // 设置是否重置所有配置,恢复全局设置默认值 m_log4qtProperties.setProperty(UKUILOG4QT_RESET, "true"); // 设置日志SDK内部记录器级别为INFO m_log4qtProperties.setProperty(UKUILOG4QT_DEBUG, "INFO"); // 设置日志记录器仓库的阈值为NULL(不限制) const QLatin1String key_threshold("log4j.threshold"); m_log4qtProperties.setProperty(key_threshold, "NULL"); // 设置是否监听QDebug输出的字符串 m_log4qtProperties.setProperty(UKUILOG4QT_HANDLEQT, "true"); // 设置根Logger的输出日志等级和输出目的地(DEBUG级别,输出到daily文件) m_log4qtProperties.setProperty(UKUILOG4QT_ROOTLOGGER, "DEBUG,daily"); // 设置控制台输出器类型 const QLatin1String key_appender_console("log4j.appender.console"); m_log4qtProperties.setProperty(key_appender_console, "org.apache.log4j.ConsoleAppender"); // 设置控制台输出目标为标准输出 const QLatin1String key_appender_console_target("log4j.appender.console.target"); m_log4qtProperties.setProperty(key_appender_console_target, "STDOUT_TARGET"); // 设置控制台输出布局为TTCCLayout(时间、线程、类别、消息) const QLatin1String key_appender_console_layout("log4j.appender.console.layout"); m_log4qtProperties.setProperty(key_appender_console_layout, "org.apache.log4j.TTCCLayout"); // 设置控制台布局的日期格式 const QLatin1String key_appender_console_layout_dateformat("log4j.appender.console.layout.dateFormat"); m_log4qtProperties.setProperty(key_appender_console_layout_dateformat, "yyy-MM-dd hh:mm:ss.zzz"); // 设置控制台布局不包含上下文信息 const QLatin1String key_appender_console_layout_contextprinting("log4j.appender.console.layout.contextPrinting"); m_log4qtProperties.setProperty(key_appender_console_layout_contextprinting, "false"); // 设置控制台布局不包含当前类目信息 const QLatin1String key_appender_console_layout_categoryprefixing( "log4j.appender.console.layout.categoryPrefixing"); m_log4qtProperties.setProperty(key_appender_console_layout_categoryprefixing, "false"); // 设置文件输出器类型为DailyRollingFileAppender(按天滚动) const QLatin1String key_appender_daily("log4j.appender.daily"); m_log4qtProperties.setProperty(key_appender_daily, "org.apache.log4j.DailyRollingFileAppender"); // 设置文件输出器的基础文件路径 const QLatin1String key_appender_daily_file("log4j.appender.daily.file"); QStringList homePath = QStandardPaths::standardLocations(QStandardPaths::HomeLocation); if (homePath.size() <= 0) { m_log4qtProperties.setProperty(key_appender_daily_file, ""); } else { // 检查目录权限 QString logDirPath = homePath[0] + UKUILOG4QT_ROOTPATH; if (!checkLogDirectoryValid(homePath[0], UKUILOG4QT_ROOTPATH)) { m_log4qtProperties.setProperty(key_appender_daily_file, ""); } else { // 构建日志文件路径:~/.log/应用程序名.log m_strBaseFilePath = logDirPath + strAppName + ".log"; m_log4qtProperties.setProperty(key_appender_daily_file, m_strBaseFilePath); } } // 设置文件输出器以追加模式写入(不覆盖现有内容) const QLatin1String key_appender_daily_appendfile("log4j.appender.daily.appendFile"); m_log4qtProperties.setProperty(key_appender_daily_appendfile, "true"); // 设置文件输出器立即刷新到磁盘(确保日志及时写入) const QLatin1String key_appender_daily_immediateflush("log4j.appender.daily.immediateFlush"); m_log4qtProperties.setProperty(key_appender_daily_immediateflush, "true"); // 设置文件滚动日期模式(按天滚动,文件名后缀格式:.yyyy-MM-dd) m_log4qtProperties.setProperty(UKUILOG4QT_DAILY_DATEPATTERN, ".yyyy-MM-dd"); // 设置文件输出器布局为PatternLayout(模式布局) const QLatin1String key_appender_daily_layout("log4j.appender.daily.layout"); m_log4qtProperties.setProperty(key_appender_daily_layout, "org.apache.log4j.PatternLayout"); // 设置文件输出器的日志格式模式 // 格式:日期时间(相对时间)[线程]|级别| - 消息内容 m_log4qtProperties.setProperty( UKUILOG4QT_DAILY_CONVERSIONPATTERN, "%d{yyyy-MM-dd HH:mm:ss,zzz}(%-4r)[%t]|%-5p| - %m%n"); initSettings(strAppName, m_log4qtProperties); // 根据配置属性初始化Log4Qt的根Logger if (!Log4Qt::PropertyConfigurator::configure(m_log4qtProperties)) { return -2; // Log4Qt配置失败,返回错误 } // 标记初始化完成 m_isInited = true; // 启动日志文件清理检查定时器 startCleanUpCheckTimer(); return 0; } /** * @brief 初始化GSettings配置并设置监听 * @param strAppName 应用程序名称 * @param properties Log4Qt属性对象引用 */ void UkuiLog4qtConfig::initSettings(QString strAppName, Log4Qt::Properties &properties) { // 读取全局GSettings配置 const QByteArray gid(UKUILOG4QT_SETTINGS); if (QGSettings::isSchemaInstalled(gid)) { m_gsLog4qtGlobal = new QGSettings(gid); // 设置全局配置变化监听器 connect(m_gsLog4qtGlobal, &QGSettings::changed, [=](QString key) { QMutexLocker locker(single_config()); QVariant gValue; bool bLogConfigChange = false; // 标记是否需要重新配置Log4Qt bool bLogRollingChange = false; // 标记是否需要重新启动清理定时器 // 处理重置配置变化 if (UKUILOG4QT_SETTINGS_RESET == key) { gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_RESET); if (gValue.isValid()) { m_log4qtProperties.setProperty(UKUILOG4QT_RESET, gValue.toString()); bLogConfigChange = true; } } // 处理调试级别配置变化 else if (UKUILOG4QT_SETTINGS_DEBUG == key) { gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_DEBUG); if (gValue.isValid()) { m_log4qtProperties.setProperty(UKUILOG4QT_DEBUG, gValue.toString()); bLogConfigChange = true; } } else if (UKUILOG4QT_SETTINGS_HANDLEQT == key) { gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_HANDLEQT); if (gValue.isValid()) { m_log4qtProperties.setProperty(UKUILOG4QT_HANDLEQT, gValue.toString()); bLogConfigChange = true; } } else if (UKUILOG4QT_SETTINGS_ROOTLOGGER == key) { gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_ROOTLOGGER); if (gValue.isValid()) { m_log4qtProperties.setProperty(UKUILOG4QT_ROOTLOGGER, gValue.toString()); bLogConfigChange = true; } } else if (UKUILOG4QT_SETTINGS_DAILY_DATEPATTERN == key) { gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_DAILY_DATEPATTERN); if (gValue.isValid()) { m_log4qtProperties.setProperty(UKUILOG4QT_DAILY_DATEPATTERN, gValue.toString()); bLogConfigChange = true; } } else if (UKUILOG4QT_SETTINGS_DAILY_CONVERSIONPATTERN == key) { gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_DAILY_CONVERSIONPATTERN); if (gValue.isValid()) { m_log4qtProperties.setProperty(UKUILOG4QT_DAILY_CONVERSIONPATTERN, gValue.toString()); bLogConfigChange = true; } } if (bLogConfigChange) { Log4Qt::PropertyConfigurator::configure(m_log4qtProperties); } if (UKUILOG4QT_SETTINGS_ROLLINGCHECK_DELAYTIME == key) { gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_ROLLINGCHECK_DELAYTIME); if (gValue.isValid()) { m_timeCheckFile = gValue.toULongLong(); bLogRollingChange = true; } } else if (UKUILOG4QT_SETTINGS_ROLLINGCHECK_MAXFILECOUNT == key) { gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_ROLLINGCHECK_MAXFILECOUNT); if (gValue.isValid()) { m_uMaxFileCount = gValue.toUInt(); bLogRollingChange = true; } } else if (UKUILOG4QT_SETTINGS_ROLLINGCHECK_MAXFILESIZE == key) { gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_ROLLINGCHECK_MAXFILESIZE); if (gValue.isValid()) { m_uMaxFileSize = gValue.toULongLong(); bLogRollingChange = true; } } if (bLogRollingChange) { startCleanUpCheckTimer(); } }); } if (m_gsLog4qtGlobal) { QVariant gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_RESET); if (gValue.isValid()) { properties.setProperty(UKUILOG4QT_RESET, gValue.toString()); } gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_DEBUG); if (gValue.isValid()) { properties.setProperty(UKUILOG4QT_DEBUG, gValue.toString()); } gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_HANDLEQT); if (gValue.isValid()) { properties.setProperty(UKUILOG4QT_HANDLEQT, gValue.toString()); } gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_ROOTLOGGER); if (gValue.isValid()) { properties.setProperty(UKUILOG4QT_ROOTLOGGER, gValue.toString()); } gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_DAILY_DATEPATTERN); if (gValue.isValid()) { properties.setProperty(UKUILOG4QT_DAILY_DATEPATTERN, gValue.toString()); } gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_DAILY_CONVERSIONPATTERN); if (gValue.isValid()) { properties.setProperty(UKUILOG4QT_DAILY_CONVERSIONPATTERN, gValue.toString()); } gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_ROLLINGCHECK_DELAYTIME); if (gValue.isValid()) { m_timeCheckFile = gValue.toULongLong(); } gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_ROLLINGCHECK_MAXFILECOUNT); if (gValue.isValid()) { m_uMaxFileCount = gValue.toUInt(); } gValue = m_gsLog4qtGlobal->get(UKUILOG4QT_SETTINGS_ROLLINGCHECK_MAXFILESIZE); if (gValue.isValid()) { m_uMaxFileSize = gValue.toULongLong(); } } //读取特例gsettings配置 QString strSpecialSetting = QString("%1-%2").arg(UKUILOG4QT_SETTINGS).arg(strAppName); const QByteArray sid = strSpecialSetting.toUtf8(); if (QGSettings::isSchemaInstalled(sid)) { m_gsLog4qtSpecial = new QGSettings(sid); connect(m_gsLog4qtSpecial, &QGSettings::changed, [=](QString key) { QMutexLocker locker(single_config()); QVariant gValue; bool bLogConfigChange = false; bool bLogRollingChange = false; if (UKUILOG4QT_SETTINGS_HANDLEQT == key) { gValue = m_gsLog4qtSpecial->get(UKUILOG4QT_SETTINGS_HANDLEQT); if (gValue.isValid()) { m_log4qtProperties.setProperty(UKUILOG4QT_HANDLEQT, gValue.toString()); bLogConfigChange = true; } } else if (UKUILOG4QT_SETTINGS_ROOTLOGGER == key) { gValue = m_gsLog4qtSpecial->get(UKUILOG4QT_SETTINGS_ROOTLOGGER); if (gValue.isValid()) { m_log4qtProperties.setProperty(UKUILOG4QT_ROOTLOGGER, gValue.toString()); bLogConfigChange = true; } } else if (UKUILOG4QT_SETTINGS_DAILY_DATEPATTERN == key) { gValue = m_gsLog4qtSpecial->get(UKUILOG4QT_SETTINGS_DAILY_DATEPATTERN); if (gValue.isValid()) { m_log4qtProperties.setProperty(UKUILOG4QT_DAILY_DATEPATTERN, gValue.toString()); bLogConfigChange = true; } } else if (UKUILOG4QT_SETTINGS_DAILY_CONVERSIONPATTERN == key) { gValue = m_gsLog4qtSpecial->get(UKUILOG4QT_SETTINGS_DAILY_CONVERSIONPATTERN); if (gValue.isValid()) { m_log4qtProperties.setProperty(UKUILOG4QT_DAILY_CONVERSIONPATTERN, gValue.toString()); bLogConfigChange = true; } } if (bLogConfigChange) { Log4Qt::PropertyConfigurator::configure(m_log4qtProperties); } if (UKUILOG4QT_SETTINGS_ROLLINGCHECK_DELAYTIME == key) { gValue = m_gsLog4qtSpecial->get(UKUILOG4QT_SETTINGS_ROLLINGCHECK_DELAYTIME); if (gValue.isValid()) { m_timeCheckFile = gValue.toULongLong(); bLogRollingChange = true; } } else if (UKUILOG4QT_SETTINGS_ROLLINGCHECK_MAXFILECOUNT == key) { gValue = m_gsLog4qtSpecial->get(UKUILOG4QT_SETTINGS_ROLLINGCHECK_MAXFILECOUNT); if (gValue.isValid()) { m_uMaxFileCount = gValue.toUInt(); bLogRollingChange = true; } } else if (UKUILOG4QT_SETTINGS_ROLLINGCHECK_MAXFILESIZE == key) { gValue = m_gsLog4qtSpecial->get(UKUILOG4QT_SETTINGS_ROLLINGCHECK_MAXFILESIZE); if (gValue.isValid()) { m_uMaxFileSize = gValue.toULongLong(); bLogRollingChange = true; } } if (bLogRollingChange) { startCleanUpCheckTimer(); } }); } if (m_gsLog4qtSpecial) { QVariant gValue = m_gsLog4qtSpecial->get(UKUILOG4QT_SETTINGS_ROOTLOGGER); if (gValue.isValid()) { properties.setProperty(UKUILOG4QT_ROOTLOGGER, gValue.toString()); } gValue = m_gsLog4qtSpecial->get(UKUILOG4QT_SETTINGS_HANDLEQT); if (gValue.isValid()) { properties.setProperty(UKUILOG4QT_HANDLEQT, gValue.toString()); } gValue = m_gsLog4qtSpecial->get(UKUILOG4QT_SETTINGS_DAILY_DATEPATTERN); if (gValue.isValid()) { properties.setProperty(UKUILOG4QT_DAILY_DATEPATTERN, gValue.toString()); } gValue = m_gsLog4qtSpecial->get(UKUILOG4QT_SETTINGS_DAILY_CONVERSIONPATTERN); if (gValue.isValid()) { properties.setProperty(UKUILOG4QT_DAILY_CONVERSIONPATTERN, gValue.toString()); } gValue = m_gsLog4qtSpecial->get(UKUILOG4QT_SETTINGS_ROLLINGCHECK_DELAYTIME); if (gValue.isValid()) { m_timeCheckFile = gValue.toULongLong(); } gValue = m_gsLog4qtSpecial->get(UKUILOG4QT_SETTINGS_ROLLINGCHECK_MAXFILECOUNT); if (gValue.isValid()) { m_uMaxFileCount = gValue.toUInt(); } gValue = m_gsLog4qtSpecial->get(UKUILOG4QT_SETTINGS_ROLLINGCHECK_MAXFILESIZE); if (gValue.isValid()) { m_uMaxFileSize = gValue.toULongLong(); } } } /** * @brief 获取日志文件列表 * @return 返回当前日志目录下的所有日志文件信息列表 */ QFileInfoList UkuiLog4qtConfig::getLogFiles() const { QFileInfoList files; // 如果没有设置基础文件路径,返回空列表 if (m_strBaseFilePath.isEmpty()) { return files; } try { // 检查基础日志文件是否存在 QFileInfo currentFileInfo(m_strBaseFilePath); if (!currentFileInfo.exists()) { return files; } // 检查日志文件所在目录是否存在 QDir dir(currentFileInfo.path()); if (!dir.exists()) { return files; } // 检查目录是否可读 QFileInfo dirInfo(currentFileInfo.path()); if (!dirInfo.isReadable()) { qWarning() << "dir couldn't access:" << currentFileInfo.path(); return files; } // 设置目录过滤器:只获取文件,排除符号链接 dir.setFilter(QDir::Files | QDir::NoSymLinks); // 构建文件名过滤器:匹配基础文件名开头的所有文件 QString baseName = currentFileInfo.baseName(); QStringList filters; filters << baseName + "*"; dir.setNameFilters(filters); // 按修改时间排序(最新的在前) dir.setSorting(QDir::Time); // 记录开始时间,用于性能监控 QTime startTime = QTime::currentTime(); files = dir.entryInfoList(); // 检查文件扫描耗时,如果超过100ms则发出警告 int elapsed = startTime.msecsTo(QTime::currentTime()); if (elapsed > 100) { qWarning() << QString("File listing took %1ms, consider increasing cleanup interval").arg(elapsed); } } catch (const std::exception &e) { qWarning() << "get log files cause exception:" << e.what(); files.clear(); } catch (...) { qWarning() << "get log files cause unknown exception"; files.clear(); } return files; } /** * @brief 检查日志目录是否有效 * @param mainDirPath 目录主路径 * @param dirName 目录名称 * @return 如果主目录存在且可读写,且子目录不存在或者存在且可读写返回true,否则返回false */ bool UkuiLog4qtConfig::checkLogDirectoryValid(const QString &mainDirPath, const QString &dirName) const { QDir dir(mainDirPath); // 如果目录已存在,检查是否可访问 if (dir.exists()) { QFileInfo dirInfo(mainDirPath); if (dirInfo.isReadable() && dirInfo.isWritable()) { QString logDirPath = mainDirPath + dirName; QDir logDir(logDirPath); if (logDir.exists()) { QFileInfo logDirInfo(logDirPath); if (logDirInfo.isReadable() && logDirInfo.isWritable()) { return true; } } else { return true; } } } return false; } /** * @brief 启动日志文件清理检查定时器 */ void UkuiLog4qtConfig::startCleanUpCheckTimer() { // 如果没有设置基础文件路径,不启动清理定时器 if (m_strBaseFilePath.isEmpty()) { return; } // 创建并启动日志文件清理检查线程 if (!m_threadCheckFile) { m_threadCheckFile = new UkuiLog4qtRolling(m_strBaseFilePath); m_threadCheckFile->start(); } // 获取当前日志文件列表并设置检查限制条件 QFileInfoList fileInfoList = getLogFiles(); if (m_threadCheckFile) { m_threadCheckFile->setFileCheckLimit(fileInfoList, m_uMaxFileCount, m_uMaxFileSize * 1024 * 1024); } if (QCoreApplication::instance()) { // 创建清理检查定时器 if (!m_cleanUpCheckTimer) { m_cleanUpCheckTimer = new QTimer(this); connect(m_cleanUpCheckTimer, &QTimer::timeout, this, &UkuiLog4qtConfig::onCleanUpCheckTimer); } // 设置定时器间隔并启动 m_cleanUpCheckTimer->setInterval(m_timeCheckFile * 1000); m_cleanUpCheckTimer->start(); } else { if (!m_isConnectToLogger) { connect( Log4Qt::LogManager::qtLogger(), &Log4Qt::Logger::logOutput, this, &UkuiLog4qtConfig::onLogOutput); m_isConnectToLogger = true; } } } void UkuiLog4qtConfig::onLogOutput() { if (QCoreApplication::instance()) { // 创建清理检查定时器 if (!m_cleanUpCheckTimer) { m_cleanUpCheckTimer = new QTimer(this); connect(m_cleanUpCheckTimer, &QTimer::timeout, this, &UkuiLog4qtConfig::onCleanUpCheckTimer); } // 设置定时器间隔并启动 m_cleanUpCheckTimer->setInterval(m_timeCheckFile * 1000); m_cleanUpCheckTimer->start(); if (m_isConnectToLogger) { disconnect( Log4Qt::LogManager::qtLogger(), &Log4Qt::Logger::logOutput, this, &UkuiLog4qtConfig::onLogOutput); } } } /** * @brief 停止日志文件清理检查定时器 */ void UkuiLog4qtConfig::stopCleanUpCheckTimer() { // 停止清理检查定时器 if (m_cleanUpCheckTimer && m_cleanUpCheckTimer->isActive()) { m_cleanUpCheckTimer->stop(); } // 停止并删除清理线程 if (m_threadCheckFile) { m_threadCheckFile->stop(); m_threadCheckFile->deleteLater(); } } /** * @brief 定时器超时槽函数 */ void UkuiLog4qtConfig::onCleanUpCheckTimer() { // 如果没有设置基础文件路径或清理线程不存在,直接返回 if (m_strBaseFilePath.isEmpty() || !m_threadCheckFile) { return; } // 重新获取日志文件列表 QFileInfoList fileInfoList = getLogFiles(); // 更新清理线程的文件检查限制条件 m_threadCheckFile->setFileCheckLimit(fileInfoList, m_uMaxFileCount, m_uMaxFileSize * 1024 * 1024); } ukui-interface/Makefile.am0000664000175000017500000000004615167726076014470 0ustar fengfengSUBDIRS = src EXTRA_DIST = autogen.sh ukui-interface/configure.ac0000664000175000017500000000216315167726076014724 0ustar fengfeng# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) AC_INIT(ukui-interface,1.0,liuhao@kylinos.cn) AM_INIT_AUTOMAKE AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADERS([config.h]) # Checks for programs. AC_PROG_CXX AC_PROG_AWK AC_PROG_CC AC_PROG_CPP AC_PROG_INSTALL AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_RANLIB AC_PROG_LIBTOOL # Checks for libraries. PKG_CHECK_MODULES(GLIB_2, glib-2.0 >= 1.00) PKG_CHECK_MODULES(GIO_2, gio-2.0 >= 1.00) PKG_CHECK_MODULES(GIO_UNIX_2, gio-unix-2.0 >= 1.00) PKG_CHECK_MODULES(QT6CORE, Qt6Core >= 6.0.0) # FIXME: Replace `main' with a function in `-lgsettings': AC_CHECK_LIB([gsettings], [main]) # FIXME: Replace `main' with a function in `-lprint': AC_CHECK_LIB([print], [main]) # Checks for header files. AC_CHECK_HEADERS([stdlib.h string.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_CHECK_HEADER_STDBOOL # Checks for library functions. AC_CHECK_FUNCS([strerror]) AC_CONFIG_FILES([Makefile src/Makefile src/common/Makefile]) AC_OUTPUT ukui-interface/AUTHORS0000664000175000017500000000003315167726064013475 0ustar fengfengliuhao ukui-interface/afltests/0000775000175000017500000000000015167726076014261 5ustar fengfengukui-interface/afltests/afltests.pro0000664000175000017500000000011215167726076016622 0ustar fengfengTEMPLATE = subdirs SUBDIRS = afltest_common \ afltest_log4qt ukui-interface/afltests/afltest_log4qt/0000775000175000017500000000000015167726076017215 5ustar fengfengukui-interface/afltests/afltest_log4qt/main.cpp0000664000175000017500000000211315167726076020642 0ustar fengfeng/* * Copyright (C) 2025 KylinSoft Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include #include "ukui-log4qt.h" #include int main(int argc, char **argv) { if (argc < 2) { puts("I need more args"); return 0; } initUkuiLog4qt(argv[1]); QCoreApplication app(argc, argv); KyDebug("debug"); KyInfo("info"); KyWarning("warning"); KyCritical("critical"); return app.exec(); } ukui-interface/afltests/afltest_log4qt/afltest_log4qt.pro0000664000175000017500000000135315167726076022675 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2019-08-22T11:12:59 # #------------------------------------------------- QT += core QT -= gui TEMPLATE = app TARGET = afltest_log4qt target.source += $$TARGET target.path = ./ #AFL++测试工具 QMAKE_CC = afl-cc QMAKE_CXX = afl-c++ QMAKE_LINK = afl-c++ QMAKE_LFLAGS += -fsanitize=fuzzer QMAKE_CXXFLAGS += -fsanitize=leak,fuzzer QMAKE_CFLAGS += -fsanitize=leak,fuzzer LIBS += LIBS += -L$$[QT_INSTALL_LIBS] CONFIG += link_pkgconfig PKGCONFIG += #log4qt include($$PWD/../../src/log4qt/ukui-log4qt.pri) # Include directories INCLUDEPATH += $$PROJECT_ROOTDIR \ $$PWD/../../src/log4qt SOURCES += fuzz_target.cpp HEADERS += ukui-interface/afltests/afltest_log4qt/fuzz_target.cpp0000664000175000017500000000233315167726076022266 0ustar fengfeng/* * Copyright (C) 2025 KylinSoft Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include #include #include #include "ukui-log4qt.h" #include #include extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { initUkuiLog4qt((const char*)(data)); int argc = 0; char** argv = nullptr; QCoreApplication app(argc, argv); KyDebug("debug"); KyInfo("info"); KyWarning("warning"); KyCritical("critical"); QTimer::singleShot(0, &app, [&](){ app.quit(); }); return app.exec(); } ukui-interface/afltests/afltest_common/0000775000175000017500000000000015167726076017273 5ustar fengfengukui-interface/afltests/afltest_common/main.cpp0000664000175000017500000000420715167726076020726 0ustar fengfeng/* * Copyright (C) 2025 KylinSoft Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include #include "kylin-com4c.h" #include "kylin-com4cxx.h" #define VALUE_MAX_LEN 128 int main(int argc, char **argv) { char value[VALUE_MAX_LEN] = {0}; if (argc < 2) { puts("I need more args"); return 0; } if (!strcmp(argv[1], "lsb")) { if (argc < 3) { puts("I need more args"); return 0; } kdk_get_lsbrelease(argv[2], value, VALUE_MAX_LEN); KDKGetLSBRelease(argv[2]); } else if (!strcmp(argv[1], "os")){ if (argc < 3) { puts("I need more args"); return 0; } kdk_get_osrelease(argv[2], value, VALUE_MAX_LEN); KDKGetOSRelease(argv[2]); } else if (!strcmp(argv[1], "kyinfo")) { if (argc < 4) { puts("I need more args"); return 0; } kdk_get_kyinfo(argv[2], argv[3], value, VALUE_MAX_LEN); KDKGetKYInfo(argv[2], argv[3]); } else if (!strcmp(argv[1], "prjname")) { kdk_get_prjcodename(value, VALUE_MAX_LEN); KDKGetPrjCodeName(); } else if (!strcmp(argv[1], "cpu")) { kdk_get_cpumodelname(value, VALUE_MAX_LEN); KDKGetCpuModelName(); } else if (!strcmp(argv[1], "spec")) { kdk_get_spechdplatform(value, VALUE_MAX_LEN); KDKGetSpecHDPlatform(); } else if (!strcmp(argv[1], "virt")) { kdk_get_virtenv(value, VALUE_MAX_LEN); KDKGetVirtEnv(); } return 0; } ukui-interface/afltests/afltest_common/fuzz_target.cpp0000664000175000017500000000426615167726076022353 0ustar fengfeng/* * Copyright (C) 2025 KylinSoft Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include #include "kylin-com4c.h" #include "kylin-com4cxx.h" #define VALUE_MAX_LEN 128 // 这是 libFuzzer 需要的入口函数 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { char value[VALUE_MAX_LEN] = {0}; // 处理lsb-release读取 kdk_get_lsbrelease((const char*)(data), value, VALUE_MAX_LEN); KDKGetLSBRelease((const char*)(data)); // 处理os-release读取 kdk_get_osrelease((const char*)(data), value, VALUE_MAX_LEN); KDKGetOSRelease((const char*)(data)); // 处理kyinfo读取 if (size >= 2) { size_t mid = (size_t)(size/2); char *str_data = (char *)malloc(mid + 1); // 分配额外的空间用于字符串终止符 if (str_data == NULL) return 0; // 内存分配失败处理 memcpy(str_data, data, mid); str_data[mid] = '\0'; // 确保字符串以 null 结尾 kdk_get_kyinfo(str_data, (const char*)(&data[mid]), value, VALUE_MAX_LEN); KDKGetKYInfo(str_data, (const char*)(&data[mid])); free(str_data); // 释放分配的内存 } // 处理prjname读取 kdk_get_prjcodename(value, VALUE_MAX_LEN); KDKGetPrjCodeName(); // 处理cpumode读取 kdk_get_cpumodelname(value, VALUE_MAX_LEN); KDKGetCpuModelName(); // 处理specplatform读取 kdk_get_spechdplatform(value, VALUE_MAX_LEN); KDKGetSpecHDPlatform(); // 处理virtual mode读取 kdk_get_virtenv(value, VALUE_MAX_LEN); KDKGetVirtEnv(); return 0; } ukui-interface/afltests/afltest_common/afltest_common.pro0000664000175000017500000000170415167726076023031 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2019-08-22T11:12:59 # #------------------------------------------------- QT += core QT -= gui TEMPLATE = app TARGET = afltest_common target.source += $$TARGET target.path = ./ #AFL++测试工具 QMAKE_CC = afl-cc QMAKE_CXX = afl-c++ QMAKE_LINK = afl-c++ QMAKE_LFLAGS += -fsanitize=fuzzer QMAKE_CXXFLAGS += -fsanitize=leak,fuzzer QMAKE_CFLAGS += -fsanitize=leak,fuzzer LIBS += -lpthread -liniparser LIBS += -L$$[QT_INSTALL_LIBS] CONFIG += link_pkgconfig PKGCONFIG += # Include directories INCLUDEPATH += $$PROJECT_ROOTDIR \ $$PWD/../../src/common SOURCES += ../../src/common/kylin-com4cxx.cpp \ ../../src/common/kylin-com4c.c \ ../../src/common/kylin-ini.c \ fuzz_target.cpp HEADERS += ../../src/common/kylin-ini.h \ ../../src/common/kylin-com4c.h \ ../../src/common/kylin-com4cxx.h ukui-interface/COPYING0000664000175000017500000010451315167726064013470 0ustar fengfeng GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . ukui-interface/README0000664000175000017500000000047315167726076013320 0ustar fengfeng# ukui interface ## API结构 初步计划API结构如下所示: ``` ukui interface结构 ├── 通用接口(common) : 从/etc/lsb-release、/etc/os-release文件读取相关信息 ├── QT日志(log4qt) : 重定向qt程序日志输出,并可配置输出等级和格式等 └── 其他功能 ``` ukui-interface/ChangeLog0000664000175000017500000000000015167726064014171 0ustar fengfengukui-interface/autogen.sh0000775000175000017500000000024715167726064014435 0ustar fengfeng#!/bin/sh #aclocal #autoconf #autoheader #libtoolize --copy #automake --copy --add-missing echo "Regenerating autotools files" autoreconf --force --install || exit 1 ukui-interface/tests/0000775000175000017500000000000015167726076013576 5ustar fengfengukui-interface/tests/kt-test-utils/0000775000175000017500000000000015167726076016327 5ustar fengfengukui-interface/tests/kt-test-utils/cpp-stub/0000775000175000017500000000000015167726076020064 5ustar fengfengukui-interface/tests/kt-test-utils/cpp-stub/addr_pri.h0000664000175000017500000002436415167726076022032 0ustar fengfeng#ifndef __ADDR_PRI_H__ #define __ADDR_PRI_H__ #include #include //base on C++11 /********************************************************** access private function **********************************************************/ namespace std { template using enable_if_t = typename enable_if::type; template using remove_reference_t = typename remove_reference::type; } // std // Unnamed namespace is used to avoid duplicate symbols if the macros are used namespace { namespace private_access_detail { // @tparam TagType, used to declare different "get" funciton overloads for // different members/statics template struct private_access { // Normal lookup cannot find in-class defined (inline) friend functions. friend PtrType get(TagType) { return PtrValue; } }; } // namespace private_access_detail } // namespace // Used macro naming conventions: // The "namespace" of this macro library is PRIVATE_ACCESS, i.e. all // macro here has this prefix. // All implementation macro, which are not meant to be used directly have the // PRIVATE_ACCESS_DETAIL prefix. // Some macros have the ABCD_IMPL form, which means they contain the // implementation details for the specific ABCD macro. #define PRIVATE_ACCESS_DETAIL_CONCATENATE_IMPL(x, y) x##y #define PRIVATE_ACCESS_DETAIL_CONCATENATE(x, y) \ PRIVATE_ACCESS_DETAIL_CONCATENATE_IMPL(x, y) // @param PtrTypeKind E.g if we have "class A", then it can be "A::*" in case of // members, or it can be "*" in case of statics. #define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, \ PtrTypeKind) \ namespace { \ namespace private_access_detail { \ /* Tag type, used to declare different get funcitons for different \ * members \ */ \ struct Tag {}; \ /* Explicit instantiation */ \ template struct private_access; \ /* We can build the PtrType only with two aliases */ \ /* E.g. using PtrType = int(int) *; would be illformed */ \ using PRIVATE_ACCESS_DETAIL_CONCATENATE(Alias_, Tag) = Type; \ using PRIVATE_ACCESS_DETAIL_CONCATENATE(PtrType_, Tag) = \ PRIVATE_ACCESS_DETAIL_CONCATENATE(Alias_, Tag) PtrTypeKind; \ /* Declare the friend function, now it is visible in namespace scope. \ * Note, \ * we could declare it inside the Tag type too, in that case ADL would \ * find \ * the declaration. By choosing to declare it here, the Tag type remains \ * a \ * simple tag type, it has no other responsibilities. */ \ PRIVATE_ACCESS_DETAIL_CONCATENATE(PtrType_, Tag) get(Tag); \ } \ } #define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FIELD(Tag, Class, Type, Name) \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, Class::*) \ namespace { \ namespace access_private_field { \ Type &Class##Name(Class &&t) { return t.*get(private_access_detail::Tag{}); } \ Type &Class##Name(Class &t) { return t.*get(private_access_detail::Tag{}); } \ /* The following usings are here to avoid duplicate const qualifier \ * warnings \ */ \ using PRIVATE_ACCESS_DETAIL_CONCATENATE(X, Tag) = Type; \ using PRIVATE_ACCESS_DETAIL_CONCATENATE(Y, Tag) = \ const PRIVATE_ACCESS_DETAIL_CONCATENATE(X, Tag); \ PRIVATE_ACCESS_DETAIL_CONCATENATE(Y, Tag) & Class##Name(const Class &t) {\ return t.*get(private_access_detail::Tag{}); \ } \ } \ } #define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FUN(Tag, Class, Type, Name) \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, Class::*) \ namespace { \ namespace call_private_fun { \ /* We do perfect forwarding, but we want to restrict the overload set \ * only for objects which have the type Class. */ \ template , \ Class>::value> * = nullptr, \ typename... Args> \ auto Class##Name(Obj &&o, Args &&... args) -> decltype( \ (std::forward(o).* \ get(private_access_detail::Tag{}))(std::forward(args)...)) { \ return (std::forward(o).*get(private_access_detail::Tag{}))( \ std::forward(args)...); \ } \ } \ namespace get_private_fun { \ auto Class##Name() -> decltype( \ get(private_access_detail::Tag{})) { \ return (get(private_access_detail::Tag{})); \ } \ } \ } #define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FIELD(Tag, Class, Type, \ Name) \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, *) \ namespace { \ namespace access_private_static_field { \ namespace Class { \ Type &Class##Name() { return *get(private_access_detail::Tag{}); } \ } \ } \ } #define PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FUN(Tag, Class, Type, \ Name) \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE(Tag, Class, Type, Name, *) \ namespace { \ namespace call_private_static_fun { \ namespace Class { \ template \ auto Class##Name(Args &&... args) -> decltype( \ get(private_access_detail::Tag{})(std::forward(args)...)) { \ return get(private_access_detail::Tag{})( \ std::forward(args)...); \ } \ } \ } \ namespace get_private_static_fun { \ namespace Class { \ auto Class##Name() -> decltype(get(private_access_detail::Tag{})) { \ return get(private_access_detail::Tag{}); \ } \ } \ } \ } #define PRIVATE_ACCESS_DETAIL_UNIQUE_TAG \ PRIVATE_ACCESS_DETAIL_CONCATENATE(PrivateAccessTag, __COUNTER__) #define ACCESS_PRIVATE_FIELD(Class, Type, Name) \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FIELD(PRIVATE_ACCESS_DETAIL_UNIQUE_TAG, \ Class, Type, Name) #define ACCESS_PRIVATE_FUN(Class, Type, Name) \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_FUN(PRIVATE_ACCESS_DETAIL_UNIQUE_TAG, \ Class, Type, Name) #define ACCESS_PRIVATE_STATIC_FIELD(Class, Type, Name) \ Type Class::Name; \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FIELD( \ PRIVATE_ACCESS_DETAIL_UNIQUE_TAG, Class, Type, Name) #define ACCESS_PRIVATE_STATIC_FUN(Class, Type, Name) \ PRIVATE_ACCESS_DETAIL_ACCESS_PRIVATE_STATIC_FUN( \ PRIVATE_ACCESS_DETAIL_UNIQUE_TAG, Class, Type, Name) #endif ukui-interface/tests/kt-test-utils/cpp-stub/addr_any.h0000664000175000017500000002113415167726076022017 0ustar fengfeng#ifndef __ADDR_ANY_H__ #define __ADDR_ANY_H__ //linux #include #include //c #include #include #include //c++ #include #include //project #include "elfio.hpp" class AddrAny { public: AddrAny() { m_init = get_exe_pathname(m_fullname); m_baseaddr = 0; } AddrAny(std::string libname) { m_init = get_lib_pathname_and_baseaddr(libname, m_fullname, m_baseaddr); } int get_local_func_addr_symtab(std::string func_name_regex_str, std::map& result) { return get_func_addr(SHT_SYMTAB, STB_LOCAL, func_name_regex_str, result); } int get_global_func_addr_symtab(std::string func_name_regex_str, std::map& result) { return get_func_addr(SHT_SYMTAB, STB_GLOBAL, func_name_regex_str, result); } int get_weak_func_addr_symtab(std::string func_name_regex_str, std::map& result) { return get_func_addr(SHT_SYMTAB, STB_WEAK, func_name_regex_str, result); } int get_global_func_addr_dynsym( std::string func_name_regex_str, std::map& result) { return get_func_addr(SHT_DYNSYM, STB_GLOBAL, func_name_regex_str, result); } int get_weak_func_addr_dynsym(std::string func_name_regex_str, std::map& result) { return get_func_addr(SHT_DYNSYM, STB_WEAK, func_name_regex_str, result); } private: bool demangle(std::string& s, std::string& name) { int status; char* pname = abi::__cxa_demangle(s.c_str(), 0, 0, &status); if (status != 0) { switch(status) { case -1: name = "memory allocation error"; break; case -2: name = "invalid name given"; break; case -3: name = "internal error: __cxa_demangle: invalid argument"; break; default: name = "unknown error occured"; break; } return false; } name = pname; free(pname); return true; } bool get_exe_pathname( std::string& name) { char line[512]; FILE *fp; uintptr_t base_addr; char perm[5]; unsigned long offset; int pathname_pos; char *pathname; size_t pathname_len; int match = 0; if(NULL == (fp = fopen("/proc/self/maps", "r"))) { return false; } while(fgets(line, sizeof(line), fp)) { if(sscanf(line, "%" PRIxPTR "-%*lx %4s %lx %*x:%*x %*d%n", &base_addr, perm, &offset, &pathname_pos) != 3) continue; if(0 != offset) continue; //get pathname while(isspace(line[pathname_pos]) && pathname_pos < (int)(sizeof(line) - 1)) pathname_pos += 1; if(pathname_pos >= (int)(sizeof(line) - 1)) continue; pathname = line + pathname_pos; pathname_len = strlen(pathname); if(0 == pathname_len) continue; if(pathname[pathname_len - 1] == '\n') { pathname[pathname_len - 1] = '\0'; pathname_len -= 1; } if(0 == pathname_len) continue; if('[' == pathname[0]) continue; name = pathname; match = 1; break; } fclose(fp); if(0 == match) { return false; } else { return true; } } bool get_lib_pathname_and_baseaddr(std::string pathname_regex_str, std::string& name, unsigned long& addr) { char line[512]; FILE *fp; uintptr_t base_addr; char perm[5]; unsigned long offset; int pathname_pos; char *pathname; size_t pathname_len; int match; regex_t pathname_regex; regcomp(&pathname_regex, pathname_regex_str.c_str(), 0); if(NULL == (fp = fopen("/proc/self/maps", "r"))) { return false; } while(fgets(line, sizeof(line), fp)) { if(sscanf(line, "%" PRIxPTR "-%*lx %4s %lx %*x:%*x %*d%n", &base_addr, perm, &offset, &pathname_pos) != 3) continue; //check permission if(perm[0] != 'r') continue; if(perm[3] != 'p') continue; //do not touch the shared memory //check offset // //We are trying to find ELF header in memory. //It can only be found at the beginning of a mapped memory regions //whose offset is 0. if(0 != offset) continue; //get pathname while(isspace(line[pathname_pos]) && pathname_pos < (int)(sizeof(line) - 1)) pathname_pos += 1; if(pathname_pos >= (int)(sizeof(line) - 1)) continue; pathname = line + pathname_pos; pathname_len = strlen(pathname); if(0 == pathname_len) continue; if(pathname[pathname_len - 1] == '\n') { pathname[pathname_len - 1] = '\0'; pathname_len -= 1; } if(0 == pathname_len) continue; if('[' == pathname[0]) continue; //check pathname //if we need to hook this elf? match = 0; if(0 == regexec(&pathname_regex, pathname, 0, NULL, 0)) { match = 1; name = pathname; addr = (unsigned long)base_addr; break; } if(0 == match) continue; } fclose(fp); if(0 == match) { return false; } else { return true; } } int get_func_addr(unsigned int ttype, unsigned int stype, std::string& func_name_regex_str, std::map& result) { // Create an elfio reader ELFIO::elfio reader; int count = 0; regex_t pathname_regex; if(!m_init) { return -1; } regcomp(&pathname_regex, func_name_regex_str.c_str(), 0); // Load ELF data if(!reader.load(m_fullname.c_str())) { return -1; } ELFIO::Elf_Half sec_num = reader.sections.size(); for(int i = 0; i < sec_num; ++i) { ELFIO::section* psec = reader.sections[i]; // Check section type if(psec->get_type() == ttype) { const ELFIO::symbol_section_accessor symbols( reader, psec ); for ( unsigned int j = 0; j < symbols.get_symbols_num(); ++j ) { std::string name; std::string name_mangle; ELFIO::Elf64_Addr value; ELFIO::Elf_Xword size; unsigned char bind; unsigned char type; ELFIO::Elf_Half section_index; unsigned char other; // Read symbol properties symbols.get_symbol( j, name, value, size, bind, type, section_index, other ); if(type == STT_FUNC && bind == stype) { bool ret = demangle(name,name_mangle); if(ret == true) { if (0 == regexec(&pathname_regex, name_mangle.c_str(), 0, NULL, 0)) { result.insert ( std::pair(name_mangle,(void*)(value + m_baseaddr))); count++; } } else { if (0 == regexec(&pathname_regex, name.c_str(), 0, NULL, 0)) { result.insert ( std::pair(name,(void*)(value + m_baseaddr))); count++; } } } } break; } } return count; } private: bool m_init; std::string m_name; std::string m_fullname; unsigned long m_baseaddr; }; #endif ukui-interface/tests/kt-test-utils/cpp-stub/elfio.hpp0000664000175000017500000045310415167726076021702 0ustar fengfeng /*** Start of inlined file: elfio_dump.hpp ***/ #ifndef ELFIO_DUMP_HPP #define ELFIO_DUMP_HPP #include #include #include #include #include /*** Start of inlined file: elfio.hpp ***/ #ifndef ELFIO_HPP #define ELFIO_HPP #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4996 ) #pragma warning( disable : 4355 ) #pragma warning( disable : 4244 ) #endif #include #include #include #include #include #include #include #include /*** Start of inlined file: elf_types.hpp ***/ #ifndef ELFTYPES_H #define ELFTYPES_H #ifndef ELFIO_NO_OWN_TYPES #if !defined( ELFIO_NO_CSTDINT ) && !defined( ELFIO_NO_INTTYPES ) #include #else typedef unsigned char uint8_t; typedef signed char int8_t; typedef unsigned short uint16_t; typedef signed short int16_t; #ifdef _MSC_VER typedef unsigned __int32 uint32_t; typedef signed __int32 int32_t; typedef unsigned __int64 uint64_t; typedef signed __int64 int64_t; #else typedef unsigned int uint32_t; typedef signed int int32_t; typedef unsigned long long uint64_t; typedef signed long long int64_t; #endif // _MSC_VER #endif // ELFIO_NO_CSTDINT #endif // ELFIO_NO_OWN_TYPES namespace ELFIO { // Attention! Platform depended definitions. typedef uint16_t Elf_Half; typedef uint32_t Elf_Word; typedef int32_t Elf_Sword; typedef uint64_t Elf_Xword; typedef int64_t Elf_Sxword; typedef uint32_t Elf32_Addr; typedef uint32_t Elf32_Off; typedef uint64_t Elf64_Addr; typedef uint64_t Elf64_Off; #define Elf32_Half Elf_Half #define Elf64_Half Elf_Half #define Elf32_Word Elf_Word #define Elf64_Word Elf_Word #define Elf32_Sword Elf_Sword #define Elf64_Sword Elf_Sword /////////////////////// // ELF Header Constants // File type #define ET_NONE 0 #define ET_REL 1 #define ET_EXEC 2 #define ET_DYN 3 #define ET_CORE 4 #define ET_LOOS 0xFE00 #define ET_HIOS 0xFEFF #define ET_LOPROC 0xFF00 #define ET_HIPROC 0xFFFF #define EM_NONE 0 // No machine #define EM_M32 1 // AT&T WE 32100 #define EM_SPARC 2 // SUN SPARC #define EM_386 3 // Intel 80386 #define EM_68K 4 // Motorola m68k family #define EM_88K 5 // Motorola m88k family #define EM_486 6 // Intel 80486// Reserved for future use #define EM_860 7 // Intel 80860 #define EM_MIPS 8 // MIPS R3000 (officially, big-endian only) #define EM_S370 9 // IBM System/370 #define EM_MIPS_RS3_LE \ 10 // MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated #define EM_res011 11 // Reserved #define EM_res012 12 // Reserved #define EM_res013 13 // Reserved #define EM_res014 14 // Reserved #define EM_PARISC 15 // HPPA #define EM_res016 16 // Reserved #define EM_VPP550 17 // Fujitsu VPP500 #define EM_SPARC32PLUS 18 // Sun's "v8plus" #define EM_960 19 // Intel 80960 #define EM_PPC 20 // PowerPC #define EM_PPC64 21 // 64-bit PowerPC #define EM_S390 22 // IBM S/390 #define EM_SPU 23 // Sony/Toshiba/IBM SPU #define EM_res024 24 // Reserved #define EM_res025 25 // Reserved #define EM_res026 26 // Reserved #define EM_res027 27 // Reserved #define EM_res028 28 // Reserved #define EM_res029 29 // Reserved #define EM_res030 30 // Reserved #define EM_res031 31 // Reserved #define EM_res032 32 // Reserved #define EM_res033 33 // Reserved #define EM_res034 34 // Reserved #define EM_res035 35 // Reserved #define EM_V800 36 // NEC V800 series #define EM_FR20 37 // Fujitsu FR20 #define EM_RH32 38 // TRW RH32 #define EM_MCORE 39 // Motorola M*Core // May also be taken by Fujitsu MMA #define EM_RCE 39 // Old name for MCore #define EM_ARM 40 // ARM #define EM_OLD_ALPHA 41 // Digital Alpha #define EM_SH 42 // Renesas (formerly Hitachi) / SuperH SH #define EM_SPARCV9 43 // SPARC v9 64-bit #define EM_TRICORE 44 // Siemens Tricore embedded processor #define EM_ARC 45 // ARC Cores #define EM_H8_300 46 // Renesas (formerly Hitachi) H8/300 #define EM_H8_300H 47 // Renesas (formerly Hitachi) H8/300H #define EM_H8S 48 // Renesas (formerly Hitachi) H8S #define EM_H8_500 49 // Renesas (formerly Hitachi) H8/500 #define EM_IA_64 50 // Intel IA-64 Processor #define EM_MIPS_X 51 // Stanford MIPS-X #define EM_COLDFIRE 52 // Motorola Coldfire #define EM_68HC12 53 // Motorola M68HC12 #define EM_MMA 54 // Fujitsu Multimedia Accelerator #define EM_PCP 55 // Siemens PCP #define EM_NCPU 56 // Sony nCPU embedded RISC processor #define EM_NDR1 57 // Denso NDR1 microprocesspr #define EM_STARCORE 58 // Motorola Star*Core processor #define EM_ME16 59 // Toyota ME16 processor #define EM_ST100 60 // STMicroelectronics ST100 processor #define EM_TINYJ 61 // Advanced Logic Corp. TinyJ embedded processor #define EM_X86_64 62 // Advanced Micro Devices X86-64 processor #define EM_PDSP 63 // Sony DSP Processor #define EM_PDP10 64 // Digital Equipment Corp. PDP-10 #define EM_PDP11 65 // Digital Equipment Corp. PDP-11 #define EM_FX66 66 // Siemens FX66 microcontroller #define EM_ST9PLUS 67 // STMicroelectronics ST9+ 8/16 bit microcontroller #define EM_ST7 68 // STMicroelectronics ST7 8-bit microcontroller #define EM_68HC16 69 // Motorola MC68HC16 Microcontroller #define EM_68HC11 70 // Motorola MC68HC11 Microcontroller #define EM_68HC08 71 // Motorola MC68HC08 Microcontroller #define EM_68HC05 72 // Motorola MC68HC05 Microcontroller #define EM_SVX 73 // Silicon Graphics SVx #define EM_ST19 74 // STMicroelectronics ST19 8-bit cpu #define EM_VAX 75 // Digital VAX #define EM_CRIS 76 // Axis Communications 32-bit embedded processor #define EM_JAVELIN 77 // Infineon Technologies 32-bit embedded cpu #define EM_FIREPATH 78 // Element 14 64-bit DSP processor #define EM_ZSP 79 // LSI Logic's 16-bit DSP processor #define EM_MMIX 80 // Donald Knuth's educational 64-bit processor #define EM_HUANY 81 // Harvard's machine-independent format #define EM_PRISM 82 // SiTera Prism #define EM_AVR 83 // Atmel AVR 8-bit microcontroller #define EM_FR30 84 // Fujitsu FR30 #define EM_D10V 85 // Mitsubishi D10V #define EM_D30V 86 // Mitsubishi D30V #define EM_V850 87 // NEC v850 #define EM_M32R 88 // Renesas M32R (formerly Mitsubishi M32R) #define EM_MN10300 89 // Matsushita MN10300 #define EM_MN10200 90 // Matsushita MN10200 #define EM_PJ 91 // picoJava #define EM_OPENRISC 92 // OpenRISC 32-bit embedded processor #define EM_ARC_A5 93 // ARC Cores Tangent-A5 #define EM_XTENSA 94 // Tensilica Xtensa Architecture #define EM_VIDEOCORE 95 // Alphamosaic VideoCore processor #define EM_TMM_GPP 96 // Thompson Multimedia General Purpose Processor #define EM_NS32K 97 // National Semiconductor 32000 series #define EM_TPC 98 // Tenor Network TPC processor #define EM_SNP1K 99 // Trebia SNP 1000 processor #define EM_ST200 100 // STMicroelectronics ST200 microcontroller #define EM_IP2K 101 // Ubicom IP2022 micro controller #define EM_MAX 102 // MAX Processor #define EM_CR 103 // National Semiconductor CompactRISC #define EM_F2MC16 104 // Fujitsu F2MC16 #define EM_MSP430 105 // TI msp430 micro controller #define EM_BLACKFIN 106 // ADI Blackfin #define EM_SE_C33 107 // S1C33 Family of Seiko Epson processors #define EM_SEP 108 // Sharp embedded microprocessor #define EM_ARCA 109 // Arca RISC Microprocessor #define EM_UNICORE \ 110 // Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University #define EM_EXCESS 111 // eXcess: 16/32/64-bit configurable embedded CPU #define EM_DXP 112 // Icera Semiconductor Inc. Deep Execution Processor #define EM_ALTERA_NIOS2 113 // Altera Nios II soft-core processor #define EM_CRX 114 // National Semiconductor CRX #define EM_XGATE 115 // Motorola XGATE embedded processor #define EM_C166 116 // Infineon C16x/XC16x processor #define EM_M16C 117 // Renesas M16C series microprocessors #define EM_DSPIC30F \ 118 // Microchip Technology dsPIC30F Digital Signal Controller #define EM_CE 119 // Freescale Communication Engine RISC core #define EM_M32C 120 // Renesas M32C series microprocessors #define EM_res121 121 // Reserved #define EM_res122 122 // Reserved #define EM_res123 123 // Reserved #define EM_res124 124 // Reserved #define EM_res125 125 // Reserved #define EM_res126 126 // Reserved #define EM_res127 127 // Reserved #define EM_res128 128 // Reserved #define EM_res129 129 // Reserved #define EM_res130 130 // Reserved #define EM_TSK3000 131 // Altium TSK3000 core #define EM_RS08 132 // Freescale RS08 embedded processor #define EM_res133 133 // Reserved #define EM_ECOG2 134 // Cyan Technology eCOG2 microprocessor #define EM_SCORE 135 // Sunplus Score #define EM_SCORE7 135 // Sunplus S+core7 RISC processor #define EM_DSP24 136 // New Japan Radio (NJR) 24-bit DSP Processor #define EM_VIDEOCORE3 137 // Broadcom VideoCore III processor #define EM_LATTICEMICO32 138 // RISC processor for Lattice FPGA architecture #define EM_SE_C17 139 // Seiko Epson C17 family #define EM_TI_C6000 140 // Texas Instruments TMS320C6000 DSP family #define EM_TI_C2000 141 // Texas Instruments TMS320C2000 DSP family #define EM_TI_C5500 142 // Texas Instruments TMS320C55x DSP family #define EM_res143 143 // Reserved #define EM_res144 144 // Reserved #define EM_res145 145 // Reserved #define EM_res146 146 // Reserved #define EM_res147 147 // Reserved #define EM_res148 148 // Reserved #define EM_res149 149 // Reserved #define EM_res150 150 // Reserved #define EM_res151 151 // Reserved #define EM_res152 152 // Reserved #define EM_res153 153 // Reserved #define EM_res154 154 // Reserved #define EM_res155 155 // Reserved #define EM_res156 156 // Reserved #define EM_res157 157 // Reserved #define EM_res158 158 // Reserved #define EM_res159 159 // Reserved #define EM_MMDSP_PLUS 160 // STMicroelectronics 64bit VLIW Data Signal Processor #define EM_CYPRESS_M8C 161 // Cypress M8C microprocessor #define EM_R32C 162 // Renesas R32C series microprocessors #define EM_TRIMEDIA 163 // NXP Semiconductors TriMedia architecture family #define EM_QDSP6 164 // QUALCOMM DSP6 Processor #define EM_8051 165 // Intel 8051 and variants #define EM_STXP7X 166 // STMicroelectronics STxP7x family #define EM_NDS32 \ 167 // Andes Technology compact code size embedded RISC processor family #define EM_ECOG1 168 // Cyan Technology eCOG1X family #define EM_ECOG1X 168 // Cyan Technology eCOG1X family #define EM_MAXQ30 169 // Dallas Semiconductor MAXQ30 Core Micro-controllers #define EM_XIMO16 170 // New Japan Radio (NJR) 16-bit DSP Processor #define EM_MANIK 171 // M2000 Reconfigurable RISC Microprocessor #define EM_CRAYNV2 172 // Cray Inc. NV2 vector architecture #define EM_RX 173 // Renesas RX family #define EM_METAG 174 // Imagination Technologies META processor architecture #define EM_MCST_ELBRUS 175 // MCST Elbrus general purpose hardware architecture #define EM_ECOG16 176 // Cyan Technology eCOG16 family #define EM_CR16 177 // National Semiconductor CompactRISC 16-bit processor #define EM_ETPU 178 // Freescale Extended Time Processing Unit #define EM_SLE9X 179 // Infineon Technologies SLE9X core #define EM_L1OM 180 // Intel L1OM #define EM_INTEL181 181 // Reserved by Intel #define EM_INTEL182 182 // Reserved by Intel #define EM_res183 183 // Reserved by ARM #define EM_res184 184 // Reserved by ARM #define EM_AVR32 185 // Atmel Corporation 32-bit microprocessor family #define EM_STM8 186 // STMicroeletronics STM8 8-bit microcontroller #define EM_TILE64 187 // Tilera TILE64 multicore architecture family #define EM_TILEPRO 188 // Tilera TILEPro multicore architecture family #define EM_MICROBLAZE 189 // Xilinx MicroBlaze 32-bit RISC soft processor core #define EM_CUDA 190 // NVIDIA CUDA architecture #define EM_TILEGX 191 // Tilera TILE-Gx multicore architecture family #define EM_CLOUDSHIELD 192 // CloudShield architecture family #define EM_COREA_1ST 193 // KIPO-KAIST Core-A 1st generation processor family #define EM_COREA_2ND 194 // KIPO-KAIST Core-A 2nd generation processor family #define EM_ARC_COMPACT2 195 // Synopsys ARCompact V2 #define EM_OPEN8 196 // Open8 8-bit RISC soft processor core #define EM_RL78 197 // Renesas RL78 family #define EM_VIDEOCORE5 198 // Broadcom VideoCore V processor #define EM_78KOR 199 // Renesas 78KOR family #define EM_56800EX 200 // Freescale 56800EX Digital Signal Controller (DSC) #define EM_BA1 201 // Beyond BA1 CPU architecture #define EM_BA2 202 // Beyond BA2 CPU architecture #define EM_XCORE 203 // XMOS xCORE processor family #define EM_MCHP_PIC 204 // Microchip 8-bit PIC(r) family #define EM_INTEL205 205 // Reserved by Intel #define EM_INTEL206 206 // Reserved by Intel #define EM_INTEL207 207 // Reserved by Intel #define EM_INTEL208 208 // Reserved by Intel #define EM_INTEL209 209 // Reserved by Intel #define EM_KM32 210 // KM211 KM32 32-bit processor #define EM_KMX32 211 // KM211 KMX32 32-bit processor #define EM_KMX16 212 // KM211 KMX16 16-bit processor #define EM_KMX8 213 // KM211 KMX8 8-bit processor #define EM_KVARC 214 // KM211 KVARC processor #define EM_CDP 215 // Paneve CDP architecture family #define EM_COGE 216 // Cognitive Smart Memory Processor #define EM_COOL 217 // iCelero CoolEngine #define EM_NORC 218 // Nanoradio Optimized RISC #define EM_CSR_KALIMBA 219 // CSR Kalimba architecture family #define EM_Z80 220 // Zilog Z80 #define EM_VISIUM 221 // Controls and Data Services VISIUMcore processor #define EM_FT32 222 // FTDI Chip FT32 high performance 32-bit RISC architecture #define EM_MOXIE 223 // Moxie processor family #define EM_AMDGPU 224 // AMD GPU architecture #define EM_RISCV 243 // RISC-V #define EM_LANAI 244 // Lanai processor #define EM_CEVA 245 // CEVA Processor Architecture Family #define EM_CEVA_X2 246 // CEVA X2 Processor Family #define EM_BPF 247 // Linux BPF – in-kernel virtual machine #define EM_GRAPHCORE_IPU 248 // Graphcore Intelligent Processing Unit #define EM_IMG1 249 // Imagination Technologies #define EM_NFP 250 // Netronome Flow Processor (P) #define EM_CSKY 252 // C-SKY processor family // File version #define EV_NONE 0 #define EV_CURRENT 1 // Identification index #define EI_MAG0 0 #define EI_MAG1 1 #define EI_MAG2 2 #define EI_MAG3 3 #define EI_CLASS 4 #define EI_DATA 5 #define EI_VERSION 6 #define EI_OSABI 7 #define EI_ABIVERSION 8 #define EI_PAD 9 #define EI_NIDENT 16 // Magic number #define ELFMAG0 0x7F #define ELFMAG1 'E' #define ELFMAG2 'L' #define ELFMAG3 'F' // File class #define ELFCLASSNONE 0 #define ELFCLASS32 1 #define ELFCLASS64 2 // Encoding #define ELFDATANONE 0 #define ELFDATA2LSB 1 #define ELFDATA2MSB 2 // OS extensions #define ELFOSABI_NONE 0 // No extensions or unspecified #define ELFOSABI_HPUX 1 // Hewlett-Packard HP-UX #define ELFOSABI_NETBSD 2 // NetBSD #define ELFOSABI_LINUX 3 // Linux #define ELFOSABI_SOLARIS 6 // Sun Solaris #define ELFOSABI_AIX 7 // AIX #define ELFOSABI_IRIX 8 // IRIX #define ELFOSABI_FREEBSD 9 // FreeBSD #define ELFOSABI_TRU64 10 // Compaq TRU64 UNIX #define ELFOSABI_MODESTO 11 // Novell Modesto #define ELFOSABI_OPENBSD 12 // Open BSD #define ELFOSABI_OPENVMS 13 // Open VMS #define ELFOSABI_NSK 14 // Hewlett-Packard Non-Stop Kernel #define ELFOSABI_AROS 15 // Amiga Research OS #define ELFOSABI_FENIXOS 16 // The FenixOS highly scalable multi-core OS // 64-255 Architecture-specific value range #define ELFOSABI_AMDGPU_HSA \ 64 // AMDGPU OS for HSA compatible compute // kernels. #define ELFOSABI_AMDGPU_PAL \ 65 // AMDGPU OS for AMD PAL compatible graphics // shaders and compute kernels. #define ELFOSABI_AMDGPU_MESA3D \ 66 // AMDGPU OS for Mesa3D compatible graphics // shaders and compute kernels. // AMDGPU specific e_flags #define EF_AMDGPU_MACH 0x0ff // AMDGPU processor selection mask. #define EF_AMDGPU_XNACK \ 0x100 // Indicates if the XNACK target feature is // enabled for all code contained in the ELF. // AMDGPU processors #define EF_AMDGPU_MACH_NONE 0x000 // Unspecified processor. #define EF_AMDGPU_MACH_R600_R600 0x001 #define EF_AMDGPU_MACH_R600_R630 0x002 #define EF_AMDGPU_MACH_R600_RS880 0x003 #define EF_AMDGPU_MACH_R600_RV670 0x004 #define EF_AMDGPU_MACH_R600_RV710 0x005 #define EF_AMDGPU_MACH_R600_RV730 0x006 #define EF_AMDGPU_MACH_R600_RV770 0x007 #define EF_AMDGPU_MACH_R600_CEDAR 0x008 #define EF_AMDGPU_MACH_R600_CYPRESS 0x009 #define EF_AMDGPU_MACH_R600_JUNIPER 0x00a #define EF_AMDGPU_MACH_R600_REDWOOD 0x00b #define EF_AMDGPU_MACH_R600_SUMO 0x00c #define EF_AMDGPU_MACH_R600_BARTS 0x00d #define EF_AMDGPU_MACH_R600_CAICOS 0x00e #define EF_AMDGPU_MACH_R600_CAYMAN 0x00f #define EF_AMDGPU_MACH_R600_TURKS 0x010 #define EF_AMDGPU_MACH_R600_RESERVED_FIRST 0x011 #define EF_AMDGPU_MACH_R600_RESERVED_LAST 0x01f #define EF_AMDGPU_MACH_R600_FIRST EF_AMDGPU_MACH_R600_R600 #define EF_AMDGPU_MACH_R600_LAST EF_AMDGPU_MACH_R600_TURKS #define EF_AMDGPU_MACH_AMDGCN_GFX600 0x020 #define EF_AMDGPU_MACH_AMDGCN_GFX601 0x021 #define EF_AMDGPU_MACH_AMDGCN_GFX700 0x022 #define EF_AMDGPU_MACH_AMDGCN_GFX701 0x023 #define EF_AMDGPU_MACH_AMDGCN_GFX702 0x024 #define EF_AMDGPU_MACH_AMDGCN_GFX703 0x025 #define EF_AMDGPU_MACH_AMDGCN_GFX704 0x026 #define EF_AMDGPU_MACH_AMDGCN_GFX801 0x028 #define EF_AMDGPU_MACH_AMDGCN_GFX802 0x029 #define EF_AMDGPU_MACH_AMDGCN_GFX803 0x02a #define EF_AMDGPU_MACH_AMDGCN_GFX810 0x02b #define EF_AMDGPU_MACH_AMDGCN_GFX900 0x02c #define EF_AMDGPU_MACH_AMDGCN_GFX902 0x02d #define EF_AMDGPU_MACH_AMDGCN_GFX904 0x02e #define EF_AMDGPU_MACH_AMDGCN_GFX906 0x02f #define EF_AMDGPU_MACH_AMDGCN_RESERVED0 0x027 #define EF_AMDGPU_MACH_AMDGCN_RESERVED1 0x030 #define EF_AMDGPU_MACH_AMDGCN_FIRST EF_AMDGPU_MACH_AMDGCN_GFX600 #define EF_AMDGPU_MACH_AMDGCN_LAST EF_AMDGPU_MACH_AMDGCN_GFX906 ///////////////////// // Sections constants // Section indexes #define SHN_UNDEF 0 #define SHN_LORESERVE 0xFF00 #define SHN_LOPROC 0xFF00 #define SHN_HIPROC 0xFF1F #define SHN_LOOS 0xFF20 #define SHN_HIOS 0xFF3F #define SHN_ABS 0xFFF1 #define SHN_COMMON 0xFFF2 #define SHN_XINDEX 0xFFFF #define SHN_HIRESERVE 0xFFFF // Section types #define SHT_NULL 0 #define SHT_PROGBITS 1 #define SHT_SYMTAB 2 #define SHT_STRTAB 3 #define SHT_RELA 4 #define SHT_HASH 5 #define SHT_DYNAMIC 6 #define SHT_NOTE 7 #define SHT_NOBITS 8 #define SHT_REL 9 #define SHT_SHLIB 10 #define SHT_DYNSYM 11 #define SHT_INIT_ARRAY 14 #define SHT_FINI_ARRAY 15 #define SHT_PREINIT_ARRAY 16 #define SHT_GROUP 17 #define SHT_SYMTAB_SHNDX 18 #define SHT_LOOS 0x60000000 #define SHT_HIOS 0x6fffffff #define SHT_LOPROC 0x70000000 #define SHT_HIPROC 0x7FFFFFFF #define SHT_LOUSER 0x80000000 #define SHT_HIUSER 0xFFFFFFFF // Section attribute flags #define SHF_WRITE 0x1 #define SHF_ALLOC 0x2 #define SHF_EXECINSTR 0x4 #define SHF_MERGE 0x10 #define SHF_STRINGS 0x20 #define SHF_INFO_LINK 0x40 #define SHF_LINK_ORDER 0x80 #define SHF_OS_NONCONFORMING 0x100 #define SHF_GROUP 0x200 #define SHF_TLS 0x400 #define SHF_MASKOS 0x0ff00000 #define SHF_MASKPROC 0xF0000000 // Section group flags #define GRP_COMDAT 0x1 #define GRP_MASKOS 0x0ff00000 #define GRP_MASKPROC 0xf0000000 // Symbol binding #define STB_LOCAL 0 #define STB_GLOBAL 1 #define STB_WEAK 2 #define STB_LOOS 10 #define STB_HIOS 12 #define STB_MULTIDEF 13 #define STB_LOPROC 13 #define STB_HIPROC 15 // Note types #define NT_AMDGPU_METADATA 1 #define NT_AMD_AMDGPU_HSA_METADATA 10 #define NT_AMD_AMDGPU_ISA 11 #define NT_AMD_AMDGPU_PAL_METADATA 12 // Symbol types #define STT_NOTYPE 0 #define STT_OBJECT 1 #define STT_FUNC 2 #define STT_SECTION 3 #define STT_FILE 4 #define STT_COMMON 5 #define STT_TLS 6 #define STT_LOOS 10 #define STT_AMDGPU_HSA_KERNEL 10 #define STT_HIOS 12 #define STT_LOPROC 13 #define STT_HIPROC 15 // Symbol visibility #define STV_DEFAULT 0 #define STV_INTERNAL 1 #define STV_HIDDEN 2 #define STV_PROTECTED 3 // Undefined name #define STN_UNDEF 0 // Relocation types #define R_386_NONE 0 #define R_X86_64_NONE 0 #define R_AMDGPU_NONE 0 #define R_386_32 1 #define R_X86_64_64 1 #define R_AMDGPU_ABS32_LO 1 #define R_386_PC32 2 #define R_X86_64_PC32 2 #define R_AMDGPU_ABS32_HI 2 #define R_386_GOT32 3 #define R_X86_64_GOT32 3 #define R_AMDGPU_ABS64 3 #define R_386_PLT32 4 #define R_X86_64_PLT32 4 #define R_AMDGPU_REL32 4 #define R_386_COPY 5 #define R_X86_64_COPY 5 #define R_AMDGPU_REL64 5 #define R_386_GLOB_DAT 6 #define R_X86_64_GLOB_DAT 6 #define R_AMDGPU_ABS32 6 #define R_386_JMP_SLOT 7 #define R_X86_64_JUMP_SLOT 7 #define R_AMDGPU_GOTPCREL 7 #define R_386_RELATIVE 8 #define R_X86_64_RELATIVE 8 #define R_AMDGPU_GOTPCREL32_LO 8 #define R_386_GOTOFF 9 #define R_X86_64_GOTPCREL 9 #define R_AMDGPU_GOTPCREL32_HI 9 #define R_386_GOTPC 10 #define R_X86_64_32 10 #define R_AMDGPU_REL32_LO 10 #define R_386_32PLT 11 #define R_X86_64_32S 11 #define R_AMDGPU_REL32_HI 11 #define R_X86_64_16 12 #define R_X86_64_PC16 13 #define R_AMDGPU_RELATIVE64 13 #define R_386_TLS_TPOFF 14 #define R_X86_64_8 14 #define R_386_TLS_IE 15 #define R_X86_64_PC8 15 #define R_386_TLS_GOTIE 16 #define R_X86_64_DTPMOD64 16 #define R_386_TLS_LE 17 #define R_X86_64_DTPOFF64 17 #define R_386_TLS_GD 18 #define R_X86_64_TPOFF64 18 #define R_386_TLS_LDM 19 #define R_X86_64_TLSGD 19 #define R_386_16 20 #define R_X86_64_TLSLD 20 #define R_386_PC16 21 #define R_X86_64_DTPOFF32 21 #define R_386_8 22 #define R_X86_64_GOTTPOFF 22 #define R_386_PC8 23 #define R_X86_64_TPOFF32 23 #define R_386_TLS_GD_32 24 #define R_X86_64_PC64 24 #define R_386_TLS_GD_PUSH 25 #define R_X86_64_GOTOFF64 25 #define R_386_TLS_GD_CALL 26 #define R_X86_64_GOTPC32 26 #define R_386_TLS_GD_POP 27 #define R_X86_64_GOT64 27 #define R_386_TLS_LDM_32 28 #define R_X86_64_GOTPCREL64 28 #define R_386_TLS_LDM_PUSH 29 #define R_X86_64_GOTPC64 29 #define R_386_TLS_LDM_CALL 30 #define R_X86_64_GOTPLT64 30 #define R_386_TLS_LDM_POP 31 #define R_X86_64_PLTOFF64 31 #define R_386_TLS_LDO_32 32 #define R_386_TLS_IE_32 33 #define R_386_TLS_LE_32 34 #define R_X86_64_GOTPC32_TLSDESC 34 #define R_386_TLS_DTPMOD32 35 #define R_X86_64_TLSDESC_CALL 35 #define R_386_TLS_DTPOFF32 36 #define R_X86_64_TLSDESC 36 #define R_386_TLS_TPOFF32 37 #define R_X86_64_IRELATIVE 37 #define R_386_SIZE32 38 #define R_386_TLS_GOTDESC 39 #define R_386_TLS_DESC_CALL 40 #define R_386_TLS_DESC 41 #define R_386_IRELATIVE 42 #define R_386_GOT32X 43 #define R_X86_64_GNU_VTINHERIT 250 #define R_X86_64_GNU_VTENTRY 251 // Segment types #define PT_NULL 0 #define PT_LOAD 1 #define PT_DYNAMIC 2 #define PT_INTERP 3 #define PT_NOTE 4 #define PT_SHLIB 5 #define PT_PHDR 6 #define PT_TLS 7 #define PT_LOOS 0x60000000 #define PT_HIOS 0x6fffffff #define PT_LOPROC 0x70000000 #define PT_HIPROC 0x7FFFFFFF // Segment flags #define PF_X 1 // Execute #define PF_W 2 // Write #define PF_R 4 // Read #define PF_MASKOS 0x0ff00000 // Unspecified #define PF_MASKPROC 0xf0000000 // Unspecified // Dynamic Array Tags #define DT_NULL 0 #define DT_NEEDED 1 #define DT_PLTRELSZ 2 #define DT_PLTGOT 3 #define DT_HASH 4 #define DT_STRTAB 5 #define DT_SYMTAB 6 #define DT_RELA 7 #define DT_RELASZ 8 #define DT_RELAENT 9 #define DT_STRSZ 10 #define DT_SYMENT 11 #define DT_INIT 12 #define DT_FINI 13 #define DT_SONAME 14 #define DT_RPATH 15 #define DT_SYMBOLIC 16 #define DT_REL 17 #define DT_RELSZ 18 #define DT_RELENT 19 #define DT_PLTREL 20 #define DT_DEBUG 21 #define DT_TEXTREL 22 #define DT_JMPREL 23 #define DT_BIND_NOW 24 #define DT_INIT_ARRAY 25 #define DT_FINI_ARRAY 26 #define DT_INIT_ARRAYSZ 27 #define DT_FINI_ARRAYSZ 28 #define DT_RUNPATH 29 #define DT_FLAGS 30 #define DT_ENCODING 32 #define DT_PREINIT_ARRAY 32 #define DT_PREINIT_ARRAYSZ 33 #define DT_MAXPOSTAGS 34 #define DT_LOOS 0x6000000D #define DT_HIOS 0x6ffff000 #define DT_LOPROC 0x70000000 #define DT_HIPROC 0x7FFFFFFF // DT_FLAGS values #define DF_ORIGIN 0x1 #define DF_SYMBOLIC 0x2 #define DF_TEXTREL 0x4 #define DF_BIND_NOW 0x8 #define DF_STATIC_TLS 0x10 // ELF file header struct Elf32_Ehdr { unsigned char e_ident[EI_NIDENT]; Elf_Half e_type; Elf_Half e_machine; Elf_Word e_version; Elf32_Addr e_entry; Elf32_Off e_phoff; Elf32_Off e_shoff; Elf_Word e_flags; Elf_Half e_ehsize; Elf_Half e_phentsize; Elf_Half e_phnum; Elf_Half e_shentsize; Elf_Half e_shnum; Elf_Half e_shstrndx; }; struct Elf64_Ehdr { unsigned char e_ident[EI_NIDENT]; Elf_Half e_type; Elf_Half e_machine; Elf_Word e_version; Elf64_Addr e_entry; Elf64_Off e_phoff; Elf64_Off e_shoff; Elf_Word e_flags; Elf_Half e_ehsize; Elf_Half e_phentsize; Elf_Half e_phnum; Elf_Half e_shentsize; Elf_Half e_shnum; Elf_Half e_shstrndx; }; // Section header struct Elf32_Shdr { Elf_Word sh_name; Elf_Word sh_type; Elf_Word sh_flags; Elf32_Addr sh_addr; Elf32_Off sh_offset; Elf_Word sh_size; Elf_Word sh_link; Elf_Word sh_info; Elf_Word sh_addralign; Elf_Word sh_entsize; }; struct Elf64_Shdr { Elf_Word sh_name; Elf_Word sh_type; Elf_Xword sh_flags; Elf64_Addr sh_addr; Elf64_Off sh_offset; Elf_Xword sh_size; Elf_Word sh_link; Elf_Word sh_info; Elf_Xword sh_addralign; Elf_Xword sh_entsize; }; // Segment header struct Elf32_Phdr { Elf_Word p_type; Elf32_Off p_offset; Elf32_Addr p_vaddr; Elf32_Addr p_paddr; Elf_Word p_filesz; Elf_Word p_memsz; Elf_Word p_flags; Elf_Word p_align; }; struct Elf64_Phdr { Elf_Word p_type; Elf_Word p_flags; Elf64_Off p_offset; Elf64_Addr p_vaddr; Elf64_Addr p_paddr; Elf_Xword p_filesz; Elf_Xword p_memsz; Elf_Xword p_align; }; // Symbol table entry struct Elf32_Sym { Elf_Word st_name; Elf32_Addr st_value; Elf_Word st_size; unsigned char st_info; unsigned char st_other; Elf_Half st_shndx; }; struct Elf64_Sym { Elf_Word st_name; unsigned char st_info; unsigned char st_other; Elf_Half st_shndx; Elf64_Addr st_value; Elf_Xword st_size; }; #define ELF_ST_BIND( i ) ( ( i ) >> 4 ) #define ELF_ST_TYPE( i ) ( (i)&0xf ) #define ELF_ST_INFO( b, t ) ( ( ( b ) << 4 ) + ( (t)&0xf ) ) #define ELF_ST_VISIBILITY( o ) ( (o)&0x3 ) // Relocation entries struct Elf32_Rel { Elf32_Addr r_offset; Elf_Word r_info; }; struct Elf32_Rela { Elf32_Addr r_offset; Elf_Word r_info; Elf_Sword r_addend; }; struct Elf64_Rel { Elf64_Addr r_offset; Elf_Xword r_info; }; struct Elf64_Rela { Elf64_Addr r_offset; Elf_Xword r_info; Elf_Sxword r_addend; }; #define ELF32_R_SYM( i ) ( ( i ) >> 8 ) #define ELF32_R_TYPE( i ) ( (unsigned char)( i ) ) #define ELF32_R_INFO( s, t ) ( ( ( s ) << 8 ) + (unsigned char)( t ) ) #define ELF64_R_SYM( i ) ( ( i ) >> 32 ) #define ELF64_R_TYPE( i ) ( (i)&0xffffffffL ) #define ELF64_R_INFO( s, t ) \ ( ( ( ( int64_t )( s ) ) << 32 ) + ( (t)&0xffffffffL ) ) // Dynamic structure struct Elf32_Dyn { Elf_Sword d_tag; union { Elf_Word d_val; Elf32_Addr d_ptr; } d_un; }; struct Elf64_Dyn { Elf_Sxword d_tag; union { Elf_Xword d_val; Elf64_Addr d_ptr; } d_un; }; } // namespace ELFIO #endif // ELFTYPES_H /*** End of inlined file: elf_types.hpp ***/ /*** Start of inlined file: elfio_version.hpp ***/ #define ELFIO_VERSION "3.8" /*** End of inlined file: elfio_version.hpp ***/ /*** Start of inlined file: elfio_utils.hpp ***/ #ifndef ELFIO_UTILS_HPP #define ELFIO_UTILS_HPP #define ELFIO_GET_ACCESS( TYPE, NAME, FIELD ) \ TYPE get_##NAME() const { return ( *convertor )( FIELD ); } #define ELFIO_SET_ACCESS( TYPE, NAME, FIELD ) \ void set_##NAME( TYPE value ) \ { \ FIELD = value; \ FIELD = ( *convertor )( FIELD ); \ } #define ELFIO_GET_SET_ACCESS( TYPE, NAME, FIELD ) \ TYPE get_##NAME() const { return ( *convertor )( FIELD ); } \ void set_##NAME( TYPE value ) \ { \ FIELD = value; \ FIELD = ( *convertor )( FIELD ); \ } #define ELFIO_GET_ACCESS_DECL( TYPE, NAME ) virtual TYPE get_##NAME() const = 0 #define ELFIO_SET_ACCESS_DECL( TYPE, NAME ) \ virtual void set_##NAME( TYPE value ) = 0 #define ELFIO_GET_SET_ACCESS_DECL( TYPE, NAME ) \ virtual TYPE get_##NAME() const = 0; \ virtual void set_##NAME( TYPE value ) = 0 namespace ELFIO { //------------------------------------------------------------------------------ class endianess_convertor { public: //------------------------------------------------------------------------------ endianess_convertor() { need_conversion = false; } //------------------------------------------------------------------------------ void setup( unsigned char elf_file_encoding ) { need_conversion = ( elf_file_encoding != get_host_encoding() ); } //------------------------------------------------------------------------------ uint64_t operator()( uint64_t value ) const { if ( !need_conversion ) { return value; } value = ( ( value & 0x00000000000000FFull ) << 56 ) | ( ( value & 0x000000000000FF00ull ) << 40 ) | ( ( value & 0x0000000000FF0000ull ) << 24 ) | ( ( value & 0x00000000FF000000ull ) << 8 ) | ( ( value & 0x000000FF00000000ull ) >> 8 ) | ( ( value & 0x0000FF0000000000ull ) >> 24 ) | ( ( value & 0x00FF000000000000ull ) >> 40 ) | ( ( value & 0xFF00000000000000ull ) >> 56 ); return value; } //------------------------------------------------------------------------------ int64_t operator()( int64_t value ) const { if ( !need_conversion ) { return value; } return ( int64_t )( *this )( (uint64_t)value ); } //------------------------------------------------------------------------------ uint32_t operator()( uint32_t value ) const { if ( !need_conversion ) { return value; } value = ( ( value & 0x000000FF ) << 24 ) | ( ( value & 0x0000FF00 ) << 8 ) | ( ( value & 0x00FF0000 ) >> 8 ) | ( ( value & 0xFF000000 ) >> 24 ); return value; } //------------------------------------------------------------------------------ int32_t operator()( int32_t value ) const { if ( !need_conversion ) { return value; } return ( int32_t )( *this )( (uint32_t)value ); } //------------------------------------------------------------------------------ uint16_t operator()( uint16_t value ) const { if ( !need_conversion ) { return value; } value = ( ( value & 0x00FF ) << 8 ) | ( ( value & 0xFF00 ) >> 8 ); return value; } //------------------------------------------------------------------------------ int16_t operator()( int16_t value ) const { if ( !need_conversion ) { return value; } return ( int16_t )( *this )( (uint16_t)value ); } //------------------------------------------------------------------------------ int8_t operator()( int8_t value ) const { return value; } //------------------------------------------------------------------------------ uint8_t operator()( uint8_t value ) const { return value; } //------------------------------------------------------------------------------ private: //------------------------------------------------------------------------------ unsigned char get_host_encoding() const { static const int tmp = 1; if ( 1 == *(const char*)&tmp ) { return ELFDATA2LSB; } else { return ELFDATA2MSB; } } //------------------------------------------------------------------------------ private: bool need_conversion; }; //------------------------------------------------------------------------------ inline uint32_t elf_hash( const unsigned char* name ) { uint32_t h = 0, g; while ( *name ) { h = ( h << 4 ) + *name++; g = h & 0xf0000000; if ( g != 0 ) h ^= g >> 24; h &= ~g; } return h; } } // namespace ELFIO #endif // ELFIO_UTILS_HPP /*** End of inlined file: elfio_utils.hpp ***/ /*** Start of inlined file: elfio_header.hpp ***/ #ifndef ELF_HEADER_HPP #define ELF_HEADER_HPP #include namespace ELFIO { class elf_header { public: virtual ~elf_header(){}; virtual bool load( std::istream& stream ) = 0; virtual bool save( std::ostream& stream ) const = 0; // ELF header functions ELFIO_GET_ACCESS_DECL( unsigned char, class ); ELFIO_GET_ACCESS_DECL( unsigned char, elf_version ); ELFIO_GET_ACCESS_DECL( unsigned char, encoding ); ELFIO_GET_ACCESS_DECL( Elf_Half, header_size ); ELFIO_GET_ACCESS_DECL( Elf_Half, section_entry_size ); ELFIO_GET_ACCESS_DECL( Elf_Half, segment_entry_size ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, version ); ELFIO_GET_SET_ACCESS_DECL( unsigned char, os_abi ); ELFIO_GET_SET_ACCESS_DECL( unsigned char, abi_version ); ELFIO_GET_SET_ACCESS_DECL( Elf_Half, type ); ELFIO_GET_SET_ACCESS_DECL( Elf_Half, machine ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, entry ); ELFIO_GET_SET_ACCESS_DECL( Elf_Half, sections_num ); ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, sections_offset ); ELFIO_GET_SET_ACCESS_DECL( Elf_Half, segments_num ); ELFIO_GET_SET_ACCESS_DECL( Elf64_Off, segments_offset ); ELFIO_GET_SET_ACCESS_DECL( Elf_Half, section_name_str_index ); }; template struct elf_header_impl_types; template <> struct elf_header_impl_types { typedef Elf32_Phdr Phdr_type; typedef Elf32_Shdr Shdr_type; static const unsigned char file_class = ELFCLASS32; }; template <> struct elf_header_impl_types { typedef Elf64_Phdr Phdr_type; typedef Elf64_Shdr Shdr_type; static const unsigned char file_class = ELFCLASS64; }; template class elf_header_impl : public elf_header { public: //------------------------------------------------------------------------------ elf_header_impl( endianess_convertor* convertor_, unsigned char encoding ) { convertor = convertor_; std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); header.e_ident[EI_MAG0] = ELFMAG0; header.e_ident[EI_MAG1] = ELFMAG1; header.e_ident[EI_MAG2] = ELFMAG2; header.e_ident[EI_MAG3] = ELFMAG3; header.e_ident[EI_CLASS] = elf_header_impl_types::file_class; header.e_ident[EI_DATA] = encoding; header.e_ident[EI_VERSION] = EV_CURRENT; header.e_version = ( *convertor )( (Elf_Word)EV_CURRENT ); header.e_ehsize = ( sizeof( header ) ); header.e_ehsize = ( *convertor )( header.e_ehsize ); header.e_shstrndx = ( *convertor )( (Elf_Half)1 ); header.e_phentsize = sizeof( typename elf_header_impl_types::Phdr_type ); header.e_shentsize = sizeof( typename elf_header_impl_types::Shdr_type ); header.e_phentsize = ( *convertor )( header.e_phentsize ); header.e_shentsize = ( *convertor )( header.e_shentsize ); } //------------------------------------------------------------------------------ bool load( std::istream& stream ) { stream.seekg( 0 ); stream.read( reinterpret_cast( &header ), sizeof( header ) ); return ( stream.gcount() == sizeof( header ) ); } //------------------------------------------------------------------------------ bool save( std::ostream& stream ) const { stream.seekp( 0 ); stream.write( reinterpret_cast( &header ), sizeof( header ) ); return stream.good(); } //------------------------------------------------------------------------------ // ELF header functions ELFIO_GET_ACCESS( unsigned char, class, header.e_ident[EI_CLASS] ); ELFIO_GET_ACCESS( unsigned char, elf_version, header.e_ident[EI_VERSION] ); ELFIO_GET_ACCESS( unsigned char, encoding, header.e_ident[EI_DATA] ); ELFIO_GET_ACCESS( Elf_Half, header_size, header.e_ehsize ); ELFIO_GET_ACCESS( Elf_Half, section_entry_size, header.e_shentsize ); ELFIO_GET_ACCESS( Elf_Half, segment_entry_size, header.e_phentsize ); ELFIO_GET_SET_ACCESS( Elf_Word, version, header.e_version ); ELFIO_GET_SET_ACCESS( unsigned char, os_abi, header.e_ident[EI_OSABI] ); ELFIO_GET_SET_ACCESS( unsigned char, abi_version, header.e_ident[EI_ABIVERSION] ); ELFIO_GET_SET_ACCESS( Elf_Half, type, header.e_type ); ELFIO_GET_SET_ACCESS( Elf_Half, machine, header.e_machine ); ELFIO_GET_SET_ACCESS( Elf_Word, flags, header.e_flags ); ELFIO_GET_SET_ACCESS( Elf_Half, section_name_str_index, header.e_shstrndx ); ELFIO_GET_SET_ACCESS( Elf64_Addr, entry, header.e_entry ); ELFIO_GET_SET_ACCESS( Elf_Half, sections_num, header.e_shnum ); ELFIO_GET_SET_ACCESS( Elf64_Off, sections_offset, header.e_shoff ); ELFIO_GET_SET_ACCESS( Elf_Half, segments_num, header.e_phnum ); ELFIO_GET_SET_ACCESS( Elf64_Off, segments_offset, header.e_phoff ); private: T header; endianess_convertor* convertor; }; } // namespace ELFIO #endif // ELF_HEADER_HPP /*** End of inlined file: elfio_header.hpp ***/ /*** Start of inlined file: elfio_section.hpp ***/ #ifndef ELFIO_SECTION_HPP #define ELFIO_SECTION_HPP #include #include #include namespace ELFIO { class section { friend class elfio; public: virtual ~section(){}; ELFIO_GET_ACCESS_DECL( Elf_Half, index ); ELFIO_GET_SET_ACCESS_DECL( std::string, name ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, flags ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, info ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, link ); ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, addr_align ); ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, entry_size ); ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, address ); ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, size ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, name_string_offset ); ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); virtual const char* get_data() const = 0; virtual void set_data( const char* pData, Elf_Word size ) = 0; virtual void set_data( const std::string& data ) = 0; virtual void append_data( const char* pData, Elf_Word size ) = 0; virtual void append_data( const std::string& data ) = 0; virtual size_t get_stream_size() const = 0; virtual void set_stream_size( size_t value ) = 0; protected: ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); ELFIO_SET_ACCESS_DECL( Elf_Half, index ); virtual void load( std::istream& stream, std::streampos header_offset ) = 0; virtual void save( std::ostream& stream, std::streampos header_offset, std::streampos data_offset ) = 0; virtual bool is_address_initialized() const = 0; }; template class section_impl : public section { public: //------------------------------------------------------------------------------ section_impl( const endianess_convertor* convertor_ ) : convertor( convertor_ ) { std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); is_address_set = false; data = 0; data_size = 0; index = 0; stream_size = 0; } //------------------------------------------------------------------------------ ~section_impl() { delete[] data; } //------------------------------------------------------------------------------ // Section info functions ELFIO_GET_SET_ACCESS( Elf_Word, type, header.sh_type ); ELFIO_GET_SET_ACCESS( Elf_Xword, flags, header.sh_flags ); ELFIO_GET_SET_ACCESS( Elf_Xword, size, header.sh_size ); ELFIO_GET_SET_ACCESS( Elf_Word, link, header.sh_link ); ELFIO_GET_SET_ACCESS( Elf_Word, info, header.sh_info ); ELFIO_GET_SET_ACCESS( Elf_Xword, addr_align, header.sh_addralign ); ELFIO_GET_SET_ACCESS( Elf_Xword, entry_size, header.sh_entsize ); ELFIO_GET_SET_ACCESS( Elf_Word, name_string_offset, header.sh_name ); ELFIO_GET_ACCESS( Elf64_Addr, address, header.sh_addr ); //------------------------------------------------------------------------------ Elf_Half get_index() const { return index; } //------------------------------------------------------------------------------ std::string get_name() const { return name; } //------------------------------------------------------------------------------ void set_name( std::string name_ ) { name = name_; } //------------------------------------------------------------------------------ void set_address( Elf64_Addr value ) { header.sh_addr = value; header.sh_addr = ( *convertor )( header.sh_addr ); is_address_set = true; } //------------------------------------------------------------------------------ bool is_address_initialized() const { return is_address_set; } //------------------------------------------------------------------------------ const char* get_data() const { return data; } //------------------------------------------------------------------------------ void set_data( const char* raw_data, Elf_Word size ) { if ( get_type() != SHT_NOBITS ) { delete[] data; data = new ( std::nothrow ) char[size]; if ( 0 != data && 0 != raw_data ) { data_size = size; std::copy( raw_data, raw_data + size, data ); } else { data_size = 0; } } set_size( data_size ); } //------------------------------------------------------------------------------ void set_data( const std::string& str_data ) { return set_data( str_data.c_str(), (Elf_Word)str_data.size() ); } //------------------------------------------------------------------------------ void append_data( const char* raw_data, Elf_Word size ) { if ( get_type() != SHT_NOBITS ) { if ( get_size() + size < data_size ) { std::copy( raw_data, raw_data + size, data + get_size() ); } else { data_size = 2 * ( data_size + size ); char* new_data = new ( std::nothrow ) char[data_size]; if ( 0 != new_data ) { std::copy( data, data + get_size(), new_data ); std::copy( raw_data, raw_data + size, new_data + get_size() ); delete[] data; data = new_data; } else { size = 0; } } set_size( get_size() + size ); } } //------------------------------------------------------------------------------ void append_data( const std::string& str_data ) { return append_data( str_data.c_str(), (Elf_Word)str_data.size() ); } //------------------------------------------------------------------------------ protected: //------------------------------------------------------------------------------ ELFIO_GET_SET_ACCESS( Elf64_Off, offset, header.sh_offset ); //------------------------------------------------------------------------------ void set_index( Elf_Half value ) { index = value; } //------------------------------------------------------------------------------ void load( std::istream& stream, std::streampos header_offset ) { std::fill_n( reinterpret_cast( &header ), sizeof( header ), '\0' ); stream.seekg( 0, stream.end ); set_stream_size( stream.tellg() ); stream.seekg( header_offset ); stream.read( reinterpret_cast( &header ), sizeof( header ) ); Elf_Xword size = get_size(); if ( 0 == data && SHT_NULL != get_type() && SHT_NOBITS != get_type() && size < get_stream_size() ) { data = new ( std::nothrow ) char[size + 1]; if ( ( 0 != size ) && ( 0 != data ) ) { stream.seekg( ( *convertor )( header.sh_offset ) ); stream.read( data, size ); data[size] = 0; // Ensure data is ended with 0 to avoid oob read data_size = size; } else { data_size = 0; } } } //------------------------------------------------------------------------------ void save( std::ostream& stream, std::streampos header_offset, std::streampos data_offset ) { if ( 0 != get_index() ) { header.sh_offset = data_offset; header.sh_offset = ( *convertor )( header.sh_offset ); } save_header( stream, header_offset ); if ( get_type() != SHT_NOBITS && get_type() != SHT_NULL && get_size() != 0 && data != 0 ) { save_data( stream, data_offset ); } } //------------------------------------------------------------------------------ private: //------------------------------------------------------------------------------ void save_header( std::ostream& stream, std::streampos header_offset ) const { stream.seekp( header_offset ); stream.write( reinterpret_cast( &header ), sizeof( header ) ); } //------------------------------------------------------------------------------ void save_data( std::ostream& stream, std::streampos data_offset ) const { stream.seekp( data_offset ); stream.write( get_data(), get_size() ); } //------------------------------------------------------------------------------ size_t get_stream_size() const { return stream_size; } //------------------------------------------------------------------------------ void set_stream_size( size_t value ) { stream_size = value; } //------------------------------------------------------------------------------ private: T header; Elf_Half index; std::string name; char* data; Elf_Word data_size; const endianess_convertor* convertor; bool is_address_set; size_t stream_size; }; } // namespace ELFIO #endif // ELFIO_SECTION_HPP /*** End of inlined file: elfio_section.hpp ***/ /*** Start of inlined file: elfio_segment.hpp ***/ #ifndef ELFIO_SEGMENT_HPP #define ELFIO_SEGMENT_HPP #include #include #include namespace ELFIO { class segment { friend class elfio; public: virtual ~segment(){}; ELFIO_GET_ACCESS_DECL( Elf_Half, index ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, type ); ELFIO_GET_SET_ACCESS_DECL( Elf_Word, flags ); ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, align ); ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, virtual_address ); ELFIO_GET_SET_ACCESS_DECL( Elf64_Addr, physical_address ); ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, file_size ); ELFIO_GET_SET_ACCESS_DECL( Elf_Xword, memory_size ); ELFIO_GET_ACCESS_DECL( Elf64_Off, offset ); virtual const char* get_data() const = 0; virtual Elf_Half add_section_index( Elf_Half index, Elf_Xword addr_align ) = 0; virtual Elf_Half get_sections_num() const = 0; virtual Elf_Half get_section_index_at( Elf_Half num ) const = 0; virtual bool is_offset_initialized() const = 0; protected: ELFIO_SET_ACCESS_DECL( Elf64_Off, offset ); ELFIO_SET_ACCESS_DECL( Elf_Half, index ); virtual const std::vector& get_sections() const = 0; virtual void load( std::istream& stream, std::streampos header_offset ) = 0; virtual void save( std::ostream& stream, std::streampos header_offset, std::streampos data_offset ) = 0; }; //------------------------------------------------------------------------------ template class segment_impl : public segment { public: //------------------------------------------------------------------------------ segment_impl( endianess_convertor* convertor_ ) : stream_size( 0 ), index( 0 ), data( 0 ), convertor( convertor_ ) { is_offset_set = false; std::fill_n( reinterpret_cast( &ph ), sizeof( ph ), '\0' ); } //------------------------------------------------------------------------------ virtual ~segment_impl() { delete[] data; } //------------------------------------------------------------------------------ // Section info functions ELFIO_GET_SET_ACCESS( Elf_Word, type, ph.p_type ); ELFIO_GET_SET_ACCESS( Elf_Word, flags, ph.p_flags ); ELFIO_GET_SET_ACCESS( Elf_Xword, align, ph.p_align ); ELFIO_GET_SET_ACCESS( Elf64_Addr, virtual_address, ph.p_vaddr ); ELFIO_GET_SET_ACCESS( Elf64_Addr, physical_address, ph.p_paddr ); ELFIO_GET_SET_ACCESS( Elf_Xword, file_size, ph.p_filesz ); ELFIO_GET_SET_ACCESS( Elf_Xword, memory_size, ph.p_memsz ); ELFIO_GET_ACCESS( Elf64_Off, offset, ph.p_offset ); size_t stream_size; //------------------------------------------------------------------------------ size_t get_stream_size() const { return stream_size; } //------------------------------------------------------------------------------ void set_stream_size( size_t value ) { stream_size = value; } //------------------------------------------------------------------------------ Elf_Half get_index() const { return index; } //------------------------------------------------------------------------------ const char* get_data() const { return data; } //------------------------------------------------------------------------------ Elf_Half add_section_index( Elf_Half sec_index, Elf_Xword addr_align ) { sections.push_back( sec_index ); if ( addr_align > get_align() ) { set_align( addr_align ); } return (Elf_Half)sections.size(); } //------------------------------------------------------------------------------ Elf_Half get_sections_num() const { return (Elf_Half)sections.size(); } //------------------------------------------------------------------------------ Elf_Half get_section_index_at( Elf_Half num ) const { if ( num < sections.size() ) { return sections[num]; } return Elf_Half( -1 ); } //------------------------------------------------------------------------------ protected: //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void set_offset( Elf64_Off value ) { ph.p_offset = value; ph.p_offset = ( *convertor )( ph.p_offset ); is_offset_set = true; } //------------------------------------------------------------------------------ bool is_offset_initialized() const { return is_offset_set; } //------------------------------------------------------------------------------ const std::vector& get_sections() const { return sections; } //------------------------------------------------------------------------------ void set_index( Elf_Half value ) { index = value; } //------------------------------------------------------------------------------ void load( std::istream& stream, std::streampos header_offset ) { stream.seekg( 0, stream.end ); set_stream_size( stream.tellg() ); stream.seekg( header_offset ); stream.read( reinterpret_cast( &ph ), sizeof( ph ) ); is_offset_set = true; if ( PT_NULL != get_type() && 0 != get_file_size() ) { stream.seekg( ( *convertor )( ph.p_offset ) ); Elf_Xword size = get_file_size(); if ( size > get_stream_size() ) { data = 0; } else { data = new (std::nothrow) char[size + 1]; if ( 0 != data ) { stream.read( data, size ); data[size] = 0; } } } } //------------------------------------------------------------------------------ void save( std::ostream& stream, std::streampos header_offset, std::streampos data_offset ) { ph.p_offset = data_offset; ph.p_offset = ( *convertor )( ph.p_offset ); stream.seekp( header_offset ); stream.write( reinterpret_cast( &ph ), sizeof( ph ) ); } //------------------------------------------------------------------------------ private: T ph; Elf_Half index; char* data; std::vector sections; endianess_convertor* convertor; bool is_offset_set; }; } // namespace ELFIO #endif // ELFIO_SEGMENT_HPP /*** End of inlined file: elfio_segment.hpp ***/ /*** Start of inlined file: elfio_strings.hpp ***/ #ifndef ELFIO_STRINGS_HPP #define ELFIO_STRINGS_HPP #include #include #include namespace ELFIO { //------------------------------------------------------------------------------ template class string_section_accessor_template { public: //------------------------------------------------------------------------------ string_section_accessor_template( S* section_ ) : string_section( section_ ) { } //------------------------------------------------------------------------------ const char* get_string( Elf_Word index ) const { if ( string_section ) { if ( index < string_section->get_size() ) { const char* data = string_section->get_data(); if ( 0 != data ) { return data + index; } } } return 0; } //------------------------------------------------------------------------------ Elf_Word add_string( const char* str ) { Elf_Word current_position = 0; if ( string_section ) { // Strings are addeded to the end of the current section data current_position = (Elf_Word)string_section->get_size(); if ( current_position == 0 ) { char empty_string = '\0'; string_section->append_data( &empty_string, 1 ); current_position++; } string_section->append_data( str, (Elf_Word)std::strlen( str ) + 1 ); } return current_position; } //------------------------------------------------------------------------------ Elf_Word add_string( const std::string& str ) { return add_string( str.c_str() ); } //------------------------------------------------------------------------------ private: S* string_section; }; using string_section_accessor = string_section_accessor_template
; using const_string_section_accessor = string_section_accessor_template; } // namespace ELFIO #endif // ELFIO_STRINGS_HPP /*** End of inlined file: elfio_strings.hpp ***/ #define ELFIO_HEADER_ACCESS_GET( TYPE, FNAME ) \ TYPE get_##FNAME() const { return header ? ( header->get_##FNAME() ) : 0; } #define ELFIO_HEADER_ACCESS_GET_SET( TYPE, FNAME ) \ TYPE get_##FNAME() const \ { \ return header ? ( header->get_##FNAME() ) : 0; \ } \ void set_##FNAME( TYPE val ) \ { \ if ( header ) { \ header->set_##FNAME( val ); \ } \ } namespace ELFIO { //------------------------------------------------------------------------------ class elfio { public: //------------------------------------------------------------------------------ elfio() : sections( this ), segments( this ) { header = 0; current_file_pos = 0; create( ELFCLASS32, ELFDATA2LSB ); } //------------------------------------------------------------------------------ ~elfio() { clean(); } //------------------------------------------------------------------------------ void create( unsigned char file_class, unsigned char encoding ) { clean(); convertor.setup( encoding ); header = create_header( file_class, encoding ); create_mandatory_sections(); } //------------------------------------------------------------------------------ bool load( const std::string& file_name ) { std::ifstream stream; stream.open( file_name.c_str(), std::ios::in | std::ios::binary ); if ( !stream ) { return false; } return load( stream ); } //------------------------------------------------------------------------------ bool load( std::istream& stream ) { clean(); unsigned char e_ident[EI_NIDENT]; // Read ELF file signature stream.read( reinterpret_cast( &e_ident ), sizeof( e_ident ) ); // Is it ELF file? if ( stream.gcount() != sizeof( e_ident ) || e_ident[EI_MAG0] != ELFMAG0 || e_ident[EI_MAG1] != ELFMAG1 || e_ident[EI_MAG2] != ELFMAG2 || e_ident[EI_MAG3] != ELFMAG3 ) { return false; } if ( ( e_ident[EI_CLASS] != ELFCLASS64 ) && ( e_ident[EI_CLASS] != ELFCLASS32 ) ) { return false; } convertor.setup( e_ident[EI_DATA] ); header = create_header( e_ident[EI_CLASS], e_ident[EI_DATA] ); if ( 0 == header ) { return false; } if ( !header->load( stream ) ) { return false; } load_sections( stream ); bool is_still_good = load_segments( stream ); return is_still_good; } //------------------------------------------------------------------------------ bool save( const std::string& file_name ) { std::ofstream stream; stream.open( file_name.c_str(), std::ios::out | std::ios::binary ); if ( !stream ) { return false; } return save( stream ); } //------------------------------------------------------------------------------ bool save( std::ostream& stream ) { if ( !stream || !header ) { return false; } bool is_still_good = true; // Define layout specific header fields // The position of the segment table is fixed after the header. // The position of the section table is variable and needs to be fixed // before saving. header->set_segments_num( segments.size() ); header->set_segments_offset( segments.size() ? header->get_header_size() : 0 ); header->set_sections_num( sections.size() ); header->set_sections_offset( 0 ); // Layout the first section right after the segment table current_file_pos = header->get_header_size() + header->get_segment_entry_size() * (Elf_Xword)header->get_segments_num(); calc_segment_alignment(); is_still_good = layout_segments_and_their_sections(); is_still_good = is_still_good && layout_sections_without_segments(); is_still_good = is_still_good && layout_section_table(); is_still_good = is_still_good && save_header( stream ); is_still_good = is_still_good && save_sections( stream ); is_still_good = is_still_good && save_segments( stream ); return is_still_good; } //------------------------------------------------------------------------------ // ELF header access functions ELFIO_HEADER_ACCESS_GET( unsigned char, class ); ELFIO_HEADER_ACCESS_GET( unsigned char, elf_version ); ELFIO_HEADER_ACCESS_GET( unsigned char, encoding ); ELFIO_HEADER_ACCESS_GET( Elf_Word, version ); ELFIO_HEADER_ACCESS_GET( Elf_Half, header_size ); ELFIO_HEADER_ACCESS_GET( Elf_Half, section_entry_size ); ELFIO_HEADER_ACCESS_GET( Elf_Half, segment_entry_size ); ELFIO_HEADER_ACCESS_GET_SET( unsigned char, os_abi ); ELFIO_HEADER_ACCESS_GET_SET( unsigned char, abi_version ); ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, type ); ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, machine ); ELFIO_HEADER_ACCESS_GET_SET( Elf_Word, flags ); ELFIO_HEADER_ACCESS_GET_SET( Elf64_Addr, entry ); ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, sections_offset ); ELFIO_HEADER_ACCESS_GET_SET( Elf64_Off, segments_offset ); ELFIO_HEADER_ACCESS_GET_SET( Elf_Half, section_name_str_index ); //------------------------------------------------------------------------------ const endianess_convertor& get_convertor() const { return convertor; } //------------------------------------------------------------------------------ Elf_Xword get_default_entry_size( Elf_Word section_type ) const { switch ( section_type ) { case SHT_RELA: if ( header->get_class() == ELFCLASS64 ) { return sizeof( Elf64_Rela ); } else { return sizeof( Elf32_Rela ); } case SHT_REL: if ( header->get_class() == ELFCLASS64 ) { return sizeof( Elf64_Rel ); } else { return sizeof( Elf32_Rel ); } case SHT_SYMTAB: if ( header->get_class() == ELFCLASS64 ) { return sizeof( Elf64_Sym ); } else { return sizeof( Elf32_Sym ); } case SHT_DYNAMIC: if ( header->get_class() == ELFCLASS64 ) { return sizeof( Elf64_Dyn ); } else { return sizeof( Elf32_Dyn ); } default: return 0; } } //------------------------------------------------------------------------------ private: bool is_offset_in_section( Elf64_Off offset, const section* sec ) const { return ( offset >= sec->get_offset() ) && ( offset < ( sec->get_offset() + sec->get_size() ) ); } //------------------------------------------------------------------------------ public: //! returns an empty string if no problems are detected, //! or a string containing an error message if problems are found std::string validate() const { // check for overlapping sections in the file for ( int i = 0; i < sections.size(); ++i ) { for ( int j = i + 1; j < sections.size(); ++j ) { const section* a = sections[i]; const section* b = sections[j]; if ( !( a->get_type() & SHT_NOBITS ) && !( b->get_type() & SHT_NOBITS ) && ( a->get_size() > 0 ) && ( b->get_size() > 0 ) && ( a->get_offset() > 0 ) && ( b->get_offset() > 0 ) ) { if ( is_offset_in_section( a->get_offset(), b ) || is_offset_in_section( a->get_offset() + a->get_size() - 1, b ) || is_offset_in_section( b->get_offset(), a ) || is_offset_in_section( b->get_offset() + b->get_size() - 1, a ) ) { return "Sections " + a->get_name() + " and " + b->get_name() + " overlap in file"; } } } } // more checks to be added here... return ""; } //------------------------------------------------------------------------------ private: //------------------------------------------------------------------------------ void clean() { delete header; header = 0; std::vector::const_iterator it; for ( it = sections_.begin(); it != sections_.end(); ++it ) { delete *it; } sections_.clear(); std::vector::const_iterator it1; for ( it1 = segments_.begin(); it1 != segments_.end(); ++it1 ) { delete *it1; } segments_.clear(); } //------------------------------------------------------------------------------ elf_header* create_header( unsigned char file_class, unsigned char encoding ) { elf_header* new_header = 0; if ( file_class == ELFCLASS64 ) { new_header = new elf_header_impl( &convertor, encoding ); } else if ( file_class == ELFCLASS32 ) { new_header = new elf_header_impl( &convertor, encoding ); } else { return 0; } return new_header; } //------------------------------------------------------------------------------ section* create_section() { section* new_section; unsigned char file_class = get_class(); if ( file_class == ELFCLASS64 ) { new_section = new section_impl( &convertor ); } else if ( file_class == ELFCLASS32 ) { new_section = new section_impl( &convertor ); } else { return 0; } new_section->set_index( (Elf_Half)sections_.size() ); sections_.push_back( new_section ); return new_section; } //------------------------------------------------------------------------------ segment* create_segment() { segment* new_segment; unsigned char file_class = header->get_class(); if ( file_class == ELFCLASS64 ) { new_segment = new segment_impl( &convertor ); } else if ( file_class == ELFCLASS32 ) { new_segment = new segment_impl( &convertor ); } else { return 0; } new_segment->set_index( (Elf_Half)segments_.size() ); segments_.push_back( new_segment ); return new_segment; } //------------------------------------------------------------------------------ void create_mandatory_sections() { // Create null section without calling to 'add_section' as no string // section containing section names exists yet section* sec0 = create_section(); sec0->set_index( 0 ); sec0->set_name( "" ); sec0->set_name_string_offset( 0 ); set_section_name_str_index( 1 ); section* shstrtab = sections.add( ".shstrtab" ); shstrtab->set_type( SHT_STRTAB ); shstrtab->set_addr_align( 1 ); } //------------------------------------------------------------------------------ Elf_Half load_sections( std::istream& stream ) { Elf_Half entry_size = header->get_section_entry_size(); Elf_Half num = header->get_sections_num(); Elf64_Off offset = header->get_sections_offset(); for ( Elf_Half i = 0; i < num; ++i ) { section* sec = create_section(); sec->load( stream, (std::streamoff)offset + (std::streampos)i * entry_size ); sec->set_index( i ); // To mark that the section is not permitted to reassign address // during layout calculation sec->set_address( sec->get_address() ); } Elf_Half shstrndx = get_section_name_str_index(); if ( SHN_UNDEF != shstrndx ) { string_section_accessor str_reader( sections[shstrndx] ); for ( Elf_Half i = 0; i < num; ++i ) { Elf_Word section_offset = sections[i]->get_name_string_offset(); const char* p = str_reader.get_string( section_offset ); if ( p != 0 ) { sections[i]->set_name( p ); } } } return num; } //------------------------------------------------------------------------------ //! Checks whether the addresses of the section entirely fall within the given segment. //! It doesn't matter if the addresses are memory addresses, or file offsets, //! they just need to be in the same address space bool is_sect_in_seg( Elf64_Off sect_begin, Elf_Xword sect_size, Elf64_Off seg_begin, Elf64_Off seg_end ) { return ( seg_begin <= sect_begin ) && ( sect_begin + sect_size <= seg_end ) && ( sect_begin < seg_end ); // this is important criteria when sect_size == 0 // Example: seg_begin=10, seg_end=12 (-> covering the bytes 10 and 11) // sect_begin=12, sect_size=0 -> shall return false! } //------------------------------------------------------------------------------ bool load_segments( std::istream& stream ) { Elf_Half entry_size = header->get_segment_entry_size(); Elf_Half num = header->get_segments_num(); Elf64_Off offset = header->get_segments_offset(); for ( Elf_Half i = 0; i < num; ++i ) { segment* seg; unsigned char file_class = header->get_class(); if ( file_class == ELFCLASS64 ) { seg = new segment_impl( &convertor ); } else if ( file_class == ELFCLASS32 ) { seg = new segment_impl( &convertor ); } else { return false; } seg->load( stream, (std::streamoff)offset + (std::streampos)i * entry_size ); seg->set_index( i ); // Add sections to the segments (similar to readelfs algorithm) Elf64_Off segBaseOffset = seg->get_offset(); Elf64_Off segEndOffset = segBaseOffset + seg->get_file_size(); Elf64_Off segVBaseAddr = seg->get_virtual_address(); Elf64_Off segVEndAddr = segVBaseAddr + seg->get_memory_size(); for ( Elf_Half j = 0; j < sections.size(); ++j ) { const section* psec = sections[j]; // SHF_ALLOC sections are matched based on the virtual address // otherwise the file offset is matched if ( ( psec->get_flags() & SHF_ALLOC ) ? is_sect_in_seg( psec->get_address(), psec->get_size(), segVBaseAddr, segVEndAddr ) : is_sect_in_seg( psec->get_offset(), psec->get_size(), segBaseOffset, segEndOffset ) ) { // Alignment of segment shall not be updated, to preserve original value // It will be re-calculated on saving. seg->add_section_index( psec->get_index(), 0 ); } } // Add section into the segments' container segments_.push_back( seg ); } return true; } //------------------------------------------------------------------------------ bool save_header( std::ostream& stream ) { return header->save( stream ); } //------------------------------------------------------------------------------ bool save_sections( std::ostream& stream ) { for ( unsigned int i = 0; i < sections_.size(); ++i ) { section* sec = sections_.at( i ); std::streampos headerPosition = (std::streamoff)header->get_sections_offset() + (std::streampos)header->get_section_entry_size() * sec->get_index(); sec->save( stream, headerPosition, sec->get_offset() ); } return true; } //------------------------------------------------------------------------------ bool save_segments( std::ostream& stream ) { for ( unsigned int i = 0; i < segments_.size(); ++i ) { segment* seg = segments_.at( i ); std::streampos headerPosition = header->get_segments_offset() + (std::streampos)header->get_segment_entry_size() * seg->get_index(); seg->save( stream, headerPosition, seg->get_offset() ); } return true; } //------------------------------------------------------------------------------ bool is_section_without_segment( unsigned int section_index ) { bool found = false; for ( unsigned int j = 0; !found && ( j < segments.size() ); ++j ) { for ( unsigned int k = 0; !found && ( k < segments[j]->get_sections_num() ); ++k ) { found = segments[j]->get_section_index_at( k ) == section_index; } } return !found; } //------------------------------------------------------------------------------ bool is_subsequence_of( segment* seg1, segment* seg2 ) { // Return 'true' if sections of seg1 are a subset of sections in seg2 const std::vector& sections1 = seg1->get_sections(); const std::vector& sections2 = seg2->get_sections(); bool found = false; if ( sections1.size() < sections2.size() ) { found = std::includes( sections2.begin(), sections2.end(), sections1.begin(), sections1.end() ); } return found; } //------------------------------------------------------------------------------ std::vector get_ordered_segments() { std::vector res; std::deque worklist; res.reserve( segments.size() ); std::copy( segments_.begin(), segments_.end(), std::back_inserter( worklist ) ); // Bring the segments which start at address 0 to the front size_t nextSlot = 0; for ( size_t i = 0; i < worklist.size(); ++i ) { if ( i != nextSlot && worklist[i]->is_offset_initialized() && worklist[i]->get_offset() == 0 ) { if ( worklist[nextSlot]->get_offset() == 0 ) { ++nextSlot; } std::swap( worklist[i], worklist[nextSlot] ); ++nextSlot; } } while ( !worklist.empty() ) { segment* seg = worklist.front(); worklist.pop_front(); size_t i = 0; for ( ; i < worklist.size(); ++i ) { if ( is_subsequence_of( seg, worklist[i] ) ) { break; } } if ( i < worklist.size() ) worklist.push_back( seg ); else res.push_back( seg ); } return res; } //------------------------------------------------------------------------------ bool layout_sections_without_segments() { for ( unsigned int i = 0; i < sections_.size(); ++i ) { if ( is_section_without_segment( i ) ) { section* sec = sections_[i]; Elf_Xword section_align = sec->get_addr_align(); if ( section_align > 1 && current_file_pos % section_align != 0 ) { current_file_pos += section_align - current_file_pos % section_align; } if ( 0 != sec->get_index() ) sec->set_offset( current_file_pos ); if ( SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() ) { current_file_pos += sec->get_size(); } } } return true; } //------------------------------------------------------------------------------ void calc_segment_alignment() { for ( std::vector::iterator s = segments_.begin(); s != segments_.end(); ++s ) { segment* seg = *s; for ( int i = 0; i < seg->get_sections_num(); ++i ) { section* sect = sections_[seg->get_section_index_at( i )]; if ( sect->get_addr_align() > seg->get_align() ) { seg->set_align( sect->get_addr_align() ); } } } } //------------------------------------------------------------------------------ bool layout_segments_and_their_sections() { std::vector worklist; std::vector section_generated( sections.size(), false ); // Get segments in a order in where segments which contain a // sub sequence of other segments are located at the end worklist = get_ordered_segments(); for ( unsigned int i = 0; i < worklist.size(); ++i ) { Elf_Xword segment_memory = 0; Elf_Xword segment_filesize = 0; Elf_Xword seg_start_pos = current_file_pos; segment* seg = worklist[i]; // Special case: PHDR segment // This segment contains the program headers but no sections if ( seg->get_type() == PT_PHDR && seg->get_sections_num() == 0 ) { seg_start_pos = header->get_segments_offset(); segment_memory = segment_filesize = header->get_segment_entry_size() * (Elf_Xword)header->get_segments_num(); } // Special case: else if ( seg->is_offset_initialized() && seg->get_offset() == 0 ) { seg_start_pos = 0; if ( seg->get_sections_num() ) { segment_memory = segment_filesize = current_file_pos; } } // New segments with not generated sections // have to be aligned else if ( seg->get_sections_num() && !section_generated[seg->get_section_index_at( 0 )] ) { Elf_Xword align = seg->get_align() > 0 ? seg->get_align() : 1; Elf64_Off cur_page_alignment = current_file_pos % align; Elf64_Off req_page_alignment = seg->get_virtual_address() % align; Elf64_Off error = req_page_alignment - cur_page_alignment; current_file_pos += ( seg->get_align() + error ) % align; seg_start_pos = current_file_pos; } else if ( seg->get_sections_num() ) { seg_start_pos = sections[seg->get_section_index_at( 0 )]->get_offset(); } // Write segment's data for ( unsigned int j = 0; j < seg->get_sections_num(); ++j ) { Elf_Half index = seg->get_section_index_at( j ); section* sec = sections[index]; // The NULL section is always generated if ( SHT_NULL == sec->get_type() ) { section_generated[index] = true; continue; } Elf_Xword secAlign = 0; // Fix up the alignment if ( !section_generated[index] && sec->is_address_initialized() && SHT_NOBITS != sec->get_type() && SHT_NULL != sec->get_type() && 0 != sec->get_size() ) { // Align the sections based on the virtual addresses // when possible (this is what matters for execution) Elf64_Off req_offset = sec->get_address() - seg->get_virtual_address(); Elf64_Off cur_offset = current_file_pos - seg_start_pos; if ( req_offset < cur_offset ) { // something has gone awfully wrong, abort! // secAlign would turn out negative, seeking backwards and overwriting previous data return false; } secAlign = req_offset - cur_offset; } else if ( !section_generated[index] && !sec->is_address_initialized() ) { // If no address has been specified then only the section // alignment constraint has to be matched Elf_Xword align = sec->get_addr_align(); if ( align == 0 ) { align = 1; } Elf64_Off error = current_file_pos % align; secAlign = ( align - error ) % align; } else if ( section_generated[index] ) { // Alignment for already generated sections secAlign = sec->get_offset() - seg_start_pos - segment_filesize; } // Determine the segment file and memory sizes // Special case .tbss section (NOBITS) in non TLS segment if ( ( sec->get_flags() & SHF_ALLOC ) && !( ( sec->get_flags() & SHF_TLS ) && ( seg->get_type() != PT_TLS ) && ( SHT_NOBITS == sec->get_type() ) ) ) segment_memory += sec->get_size() + secAlign; if ( SHT_NOBITS != sec->get_type() ) segment_filesize += sec->get_size() + secAlign; // Nothing to be done when generating nested segments if ( section_generated[index] ) { continue; } current_file_pos += secAlign; // Set the section addresses when missing if ( !sec->is_address_initialized() ) sec->set_address( seg->get_virtual_address() + current_file_pos - seg_start_pos ); if ( 0 != sec->get_index() ) sec->set_offset( current_file_pos ); if ( SHT_NOBITS != sec->get_type() ) current_file_pos += sec->get_size(); section_generated[index] = true; } seg->set_file_size( segment_filesize ); // If we already have a memory size from loading an elf file (value > 0), // it must not shrink! // Memory size may be bigger than file size and it is the loader's job to do something // with the surplus bytes in memory, like initializing them with a defined value. if ( seg->get_memory_size() < segment_memory ) { seg->set_memory_size( segment_memory ); } seg->set_offset( seg_start_pos ); } return true; } //------------------------------------------------------------------------------ bool layout_section_table() { // Simply place the section table at the end for now Elf64_Off alignmentError = current_file_pos % 4; current_file_pos += ( 4 - alignmentError ) % 4; header->set_sections_offset( current_file_pos ); return true; } //------------------------------------------------------------------------------ public: friend class Sections; class Sections { public: //------------------------------------------------------------------------------ Sections( elfio* parent_ ) : parent( parent_ ) {} //------------------------------------------------------------------------------ Elf_Half size() const { return (Elf_Half)parent->sections_.size(); } //------------------------------------------------------------------------------ section* operator[]( unsigned int index ) const { section* sec = 0; if ( index < parent->sections_.size() ) { sec = parent->sections_[index]; } return sec; } //------------------------------------------------------------------------------ section* operator[]( const std::string& name ) const { section* sec = 0; std::vector::const_iterator it; for ( it = parent->sections_.begin(); it != parent->sections_.end(); ++it ) { if ( ( *it )->get_name() == name ) { sec = *it; break; } } return sec; } //------------------------------------------------------------------------------ section* add( const std::string& name ) { section* new_section = parent->create_section(); new_section->set_name( name ); Elf_Half str_index = parent->get_section_name_str_index(); section* string_table( parent->sections_[str_index] ); string_section_accessor str_writer( string_table ); Elf_Word pos = str_writer.add_string( name ); new_section->set_name_string_offset( pos ); return new_section; } //------------------------------------------------------------------------------ std::vector::iterator begin() { return parent->sections_.begin(); } //------------------------------------------------------------------------------ std::vector::iterator end() { return parent->sections_.end(); } //------------------------------------------------------------------------------ std::vector::const_iterator begin() const { return parent->sections_.cbegin(); } //------------------------------------------------------------------------------ std::vector::const_iterator end() const { return parent->sections_.cend(); } //------------------------------------------------------------------------------ private: elfio* parent; } sections; //------------------------------------------------------------------------------ public: friend class Segments; class Segments { public: //------------------------------------------------------------------------------ Segments( elfio* parent_ ) : parent( parent_ ) {} //------------------------------------------------------------------------------ Elf_Half size() const { return (Elf_Half)parent->segments_.size(); } //------------------------------------------------------------------------------ segment* operator[]( unsigned int index ) const { return parent->segments_[index]; } //------------------------------------------------------------------------------ segment* add() { return parent->create_segment(); } //------------------------------------------------------------------------------ std::vector::iterator begin() { return parent->segments_.begin(); } //------------------------------------------------------------------------------ std::vector::iterator end() { return parent->segments_.end(); } //------------------------------------------------------------------------------ std::vector::const_iterator begin() const { return parent->segments_.cbegin(); } //------------------------------------------------------------------------------ std::vector::const_iterator end() const { return parent->segments_.cend(); } //------------------------------------------------------------------------------ private: elfio* parent; } segments; //------------------------------------------------------------------------------ private: elf_header* header; std::vector sections_; std::vector segments_; endianess_convertor convertor; Elf_Xword current_file_pos; }; } // namespace ELFIO /*** Start of inlined file: elfio_symbols.hpp ***/ #ifndef ELFIO_SYMBOLS_HPP #define ELFIO_SYMBOLS_HPP namespace ELFIO { //------------------------------------------------------------------------------ template class symbol_section_accessor_template { public: //------------------------------------------------------------------------------ symbol_section_accessor_template( const elfio& elf_file_, S* symbol_section_ ) : elf_file( elf_file_ ), symbol_section( symbol_section_ ) { find_hash_section(); } //------------------------------------------------------------------------------ Elf_Xword get_symbols_num() const { Elf_Xword nRet = 0; if ( 0 != symbol_section->get_entry_size() ) { nRet = symbol_section->get_size() / symbol_section->get_entry_size(); } return nRet; } //------------------------------------------------------------------------------ bool get_symbol( Elf_Xword index, std::string& name, Elf64_Addr& value, Elf_Xword& size, unsigned char& bind, unsigned char& type, Elf_Half& section_index, unsigned char& other ) const { bool ret = false; if ( elf_file.get_class() == ELFCLASS32 ) { ret = generic_get_symbol( index, name, value, size, bind, type, section_index, other ); } else { ret = generic_get_symbol( index, name, value, size, bind, type, section_index, other ); } return ret; } //------------------------------------------------------------------------------ bool get_symbol( const std::string& name, Elf64_Addr& value, Elf_Xword& size, unsigned char& bind, unsigned char& type, Elf_Half& section_index, unsigned char& other ) const { bool ret = false; if ( 0 != get_hash_table_index() ) { Elf_Word nbucket = *(const Elf_Word*)hash_section->get_data(); Elf_Word nchain = *(const Elf_Word*)( hash_section->get_data() + sizeof( Elf_Word ) ); Elf_Word val = elf_hash( (const unsigned char*)name.c_str() ); Elf_Word y = *(const Elf_Word*)( hash_section->get_data() + ( 2 + val % nbucket ) * sizeof( Elf_Word ) ); std::string str; get_symbol( y, str, value, size, bind, type, section_index, other ); while ( str != name && STN_UNDEF != y && y < nchain ) { y = *(const Elf_Word*)( hash_section->get_data() + ( 2 + nbucket + y ) * sizeof( Elf_Word ) ); get_symbol( y, str, value, size, bind, type, section_index, other ); } if ( str == name ) { ret = true; } } else { for ( Elf_Xword i = 0; i < get_symbols_num() && !ret; i++ ) { std::string symbol_name; if ( get_symbol( i, symbol_name, value, size, bind, type, section_index, other ) ) { if ( symbol_name == name ) { ret = true; } } } } return ret; } //------------------------------------------------------------------------------ bool get_symbol( const Elf64_Addr& value, std::string& name, Elf_Xword& size, unsigned char& bind, unsigned char& type, Elf_Half& section_index, unsigned char& other ) const { const endianess_convertor& convertor = elf_file.get_convertor(); Elf_Xword idx = 0; bool match = false; Elf64_Addr v = 0; if ( elf_file.get_class() == ELFCLASS32 ) { match = generic_search_symbols( [&]( const Elf32_Sym* sym ) { return convertor( sym->st_value ) == value; }, idx ); } else { match = generic_search_symbols( [&]( const Elf64_Sym* sym ) { return convertor( sym->st_value ) == value; }, idx ); } if ( match ) { return get_symbol( idx, name, v, size, bind, type, section_index, other ); } return false; } //------------------------------------------------------------------------------ Elf_Word add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, unsigned char info, unsigned char other, Elf_Half shndx ) { Elf_Word nRet; if ( symbol_section->get_size() == 0 ) { if ( elf_file.get_class() == ELFCLASS32 ) { nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); } else { nRet = generic_add_symbol( 0, 0, 0, 0, 0, 0 ); } } if ( elf_file.get_class() == ELFCLASS32 ) { nRet = generic_add_symbol( name, value, size, info, other, shndx ); } else { nRet = generic_add_symbol( name, value, size, info, other, shndx ); } return nRet; } //------------------------------------------------------------------------------ Elf_Word add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, unsigned char bind, unsigned char type, unsigned char other, Elf_Half shndx ) { return add_symbol( name, value, size, ELF_ST_INFO( bind, type ), other, shndx ); } //------------------------------------------------------------------------------ Elf_Word add_symbol( string_section_accessor& pStrWriter, const char* str, Elf64_Addr value, Elf_Xword size, unsigned char info, unsigned char other, Elf_Half shndx ) { Elf_Word index = pStrWriter.add_string( str ); return add_symbol( index, value, size, info, other, shndx ); } //------------------------------------------------------------------------------ Elf_Word add_symbol( string_section_accessor& pStrWriter, const char* str, Elf64_Addr value, Elf_Xword size, unsigned char bind, unsigned char type, unsigned char other, Elf_Half shndx ) { return add_symbol( pStrWriter, str, value, size, ELF_ST_INFO( bind, type ), other, shndx ); } //------------------------------------------------------------------------------ Elf_Xword arrange_local_symbols( std::function func = nullptr ) { int nRet = 0; if ( elf_file.get_class() == ELFCLASS32 ) { nRet = generic_arrange_local_symbols( func ); } else { nRet = generic_arrange_local_symbols( func ); } return nRet; } //------------------------------------------------------------------------------ private: //------------------------------------------------------------------------------ void find_hash_section() { hash_section = 0; hash_section_index = 0; Elf_Half nSecNo = elf_file.sections.size(); for ( Elf_Half i = 0; i < nSecNo && 0 == hash_section_index; ++i ) { const section* sec = elf_file.sections[i]; if ( sec->get_link() == symbol_section->get_index() ) { hash_section = sec; hash_section_index = i; } } } //------------------------------------------------------------------------------ Elf_Half get_string_table_index() const { return (Elf_Half)symbol_section->get_link(); } //------------------------------------------------------------------------------ Elf_Half get_hash_table_index() const { return hash_section_index; } //------------------------------------------------------------------------------ template const T* generic_get_symbol_ptr( Elf_Xword index ) const { if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) { const T* pSym = reinterpret_cast( symbol_section->get_data() + index * symbol_section->get_entry_size() ); return pSym; } return nullptr; } //------------------------------------------------------------------------------ template bool generic_search_symbols( std::function match, Elf_Xword& idx ) const { for ( Elf_Xword i = 0; i < get_symbols_num(); i++ ) { const T* symPtr = generic_get_symbol_ptr( i ); if ( symPtr == nullptr ) return false; if ( match( symPtr ) ) { idx = i; return true; } } return false; } //------------------------------------------------------------------------------ template bool generic_get_symbol( Elf_Xword index, std::string& name, Elf64_Addr& value, Elf_Xword& size, unsigned char& bind, unsigned char& type, Elf_Half& section_index, unsigned char& other ) const { bool ret = false; if ( 0 != symbol_section->get_data() && index < get_symbols_num() ) { const T* pSym = reinterpret_cast( symbol_section->get_data() + index * symbol_section->get_entry_size() ); const endianess_convertor& convertor = elf_file.get_convertor(); section* string_section = elf_file.sections[get_string_table_index()]; string_section_accessor str_reader( string_section ); const char* pStr = str_reader.get_string( convertor( pSym->st_name ) ); if ( 0 != pStr ) { name = pStr; } value = convertor( pSym->st_value ); size = convertor( pSym->st_size ); bind = ELF_ST_BIND( pSym->st_info ); type = ELF_ST_TYPE( pSym->st_info ); section_index = convertor( pSym->st_shndx ); other = pSym->st_other; ret = true; } return ret; } //------------------------------------------------------------------------------ template Elf_Word generic_add_symbol( Elf_Word name, Elf64_Addr value, Elf_Xword size, unsigned char info, unsigned char other, Elf_Half shndx ) { const endianess_convertor& convertor = elf_file.get_convertor(); T entry; entry.st_name = convertor( name ); entry.st_value = value; entry.st_value = convertor( entry.st_value ); entry.st_size = size; entry.st_size = convertor( entry.st_size ); entry.st_info = convertor( info ); entry.st_other = convertor( other ); entry.st_shndx = convertor( shndx ); symbol_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); Elf_Word nRet = symbol_section->get_size() / sizeof( entry ) - 1; return nRet; } //------------------------------------------------------------------------------ template Elf_Xword generic_arrange_local_symbols( std::function func ) { const endianess_convertor& convertor = elf_file.get_convertor(); const Elf_Xword size = symbol_section->get_entry_size(); Elf_Xword first_not_local = 1; // Skip the first entry. It is always NOTYPE Elf_Xword current = 0; Elf_Xword count = get_symbols_num(); while ( true ) { T* p1 = nullptr; T* p2 = nullptr; while ( first_not_local < count ) { p1 = const_cast( generic_get_symbol_ptr( first_not_local ) ); if ( ELF_ST_BIND( convertor( p1->st_info ) ) != STB_LOCAL ) break; ++first_not_local; } current = first_not_local + 1; while ( current < count ) { p2 = const_cast( generic_get_symbol_ptr( current ) ); if ( ELF_ST_BIND( convertor( p2->st_info ) ) == STB_LOCAL ) break; ++current; } if ( first_not_local < count && current < count ) { if ( func ) func( first_not_local, current ); // Swap the symbols T tmp; std::copy( p1, p1 + 1, &tmp ); std::copy( p2, p2 + 1, p1 ); std::copy( &tmp, &tmp + 1, p2 ); } else { // Update 'info' field of the section symbol_section->set_info( first_not_local ); break; } } // Elf_Word nRet = symbol_section->get_size() / sizeof(entry) - 1; return first_not_local; } //------------------------------------------------------------------------------ private: const elfio& elf_file; S* symbol_section; Elf_Half hash_section_index; const section* hash_section; }; using symbol_section_accessor = symbol_section_accessor_template
; using const_symbol_section_accessor = symbol_section_accessor_template; } // namespace ELFIO #endif // ELFIO_SYMBOLS_HPP /*** End of inlined file: elfio_symbols.hpp ***/ /*** Start of inlined file: elfio_note.hpp ***/ #ifndef ELFIO_NOTE_HPP #define ELFIO_NOTE_HPP namespace ELFIO { //------------------------------------------------------------------------------ // There are discrepancies in documentations. SCO documentation // (http://www.sco.com/developers/gabi/latest/ch5.pheader.html#note_section) // requires 8 byte entries alignment for 64-bit ELF file, // but Oracle's definition uses the same structure // for 32-bit and 64-bit formats. // (https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter6-18048.html) // // It looks like EM_X86_64 Linux implementation is similar to Oracle's // definition. Therefore, the same alignment works for both formats //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ template class note_section_accessor_template { public: //------------------------------------------------------------------------------ note_section_accessor_template( const elfio& elf_file_, S* section_ ) : elf_file( elf_file_ ), note_section( section_ ) { process_section(); } //------------------------------------------------------------------------------ Elf_Word get_notes_num() const { return (Elf_Word)note_start_positions.size(); } //------------------------------------------------------------------------------ bool get_note( Elf_Word index, Elf_Word& type, std::string& name, void*& desc, Elf_Word& descSize ) const { if ( index >= note_section->get_size() ) { return false; } const char* pData = note_section->get_data() + note_start_positions[index]; int align = sizeof( Elf_Word ); const endianess_convertor& convertor = elf_file.get_convertor(); type = convertor( *(const Elf_Word*)( pData + 2 * align ) ); Elf_Word namesz = convertor( *(const Elf_Word*)( pData ) ); descSize = convertor( *(const Elf_Word*)( pData + sizeof( namesz ) ) ); Elf_Xword max_name_size = note_section->get_size() - note_start_positions[index]; if ( namesz < 1 || namesz > max_name_size || (Elf_Xword)namesz + descSize > max_name_size ) { return false; } name.assign( pData + 3 * align, namesz - 1 ); if ( 0 == descSize ) { desc = 0; } else { desc = const_cast( pData + 3 * align + ( ( namesz + align - 1 ) / align ) * align ); } return true; } //------------------------------------------------------------------------------ void add_note( Elf_Word type, const std::string& name, const void* desc, Elf_Word descSize ) { const endianess_convertor& convertor = elf_file.get_convertor(); int align = sizeof( Elf_Word ); Elf_Word nameLen = (Elf_Word)name.size() + 1; Elf_Word nameLenConv = convertor( nameLen ); std::string buffer( reinterpret_cast( &nameLenConv ), align ); Elf_Word descSizeConv = convertor( descSize ); buffer.append( reinterpret_cast( &descSizeConv ), align ); type = convertor( type ); buffer.append( reinterpret_cast( &type ), align ); buffer.append( name ); buffer.append( 1, '\x00' ); const char pad[] = { '\0', '\0', '\0', '\0' }; if ( nameLen % align != 0 ) { buffer.append( pad, align - nameLen % align ); } if ( desc != 0 && descSize != 0 ) { buffer.append( reinterpret_cast( desc ), descSize ); if ( descSize % align != 0 ) { buffer.append( pad, align - descSize % align ); } } note_start_positions.push_back( note_section->get_size() ); note_section->append_data( buffer ); } private: //------------------------------------------------------------------------------ void process_section() { const endianess_convertor& convertor = elf_file.get_convertor(); const char* data = note_section->get_data(); Elf_Xword size = note_section->get_size(); Elf_Xword current = 0; note_start_positions.clear(); // Is it empty? if ( 0 == data || 0 == size ) { return; } Elf_Word align = sizeof( Elf_Word ); while ( current + (Elf_Xword)3 * align <= size ) { note_start_positions.push_back( current ); Elf_Word namesz = convertor( *(const Elf_Word*)( data + current ) ); Elf_Word descsz = convertor( *(const Elf_Word*)( data + current + sizeof( namesz ) ) ); current += (Elf_Xword)3 * sizeof( Elf_Word ) + ( ( namesz + align - 1 ) / align ) * (Elf_Xword)align + ( ( descsz + align - 1 ) / align ) * (Elf_Xword)align; } } //------------------------------------------------------------------------------ private: const elfio& elf_file; S* note_section; std::vector note_start_positions; }; using note_section_accessor = note_section_accessor_template
; using const_note_section_accessor = note_section_accessor_template; } // namespace ELFIO #endif // ELFIO_NOTE_HPP /*** End of inlined file: elfio_note.hpp ***/ /*** Start of inlined file: elfio_relocation.hpp ***/ #ifndef ELFIO_RELOCATION_HPP #define ELFIO_RELOCATION_HPP namespace ELFIO { template struct get_sym_and_type; template <> struct get_sym_and_type { static int get_r_sym( Elf_Xword info ) { return ELF32_R_SYM( (Elf_Word)info ); } static int get_r_type( Elf_Xword info ) { return ELF32_R_TYPE( (Elf_Word)info ); } }; template <> struct get_sym_and_type { static int get_r_sym( Elf_Xword info ) { return ELF32_R_SYM( (Elf_Word)info ); } static int get_r_type( Elf_Xword info ) { return ELF32_R_TYPE( (Elf_Word)info ); } }; template <> struct get_sym_and_type { static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); } static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); } }; template <> struct get_sym_and_type { static int get_r_sym( Elf_Xword info ) { return ELF64_R_SYM( info ); } static int get_r_type( Elf_Xword info ) { return ELF64_R_TYPE( info ); } }; //------------------------------------------------------------------------------ template class relocation_section_accessor_template { public: //------------------------------------------------------------------------------ relocation_section_accessor_template( const elfio& elf_file_, S* section_ ) : elf_file( elf_file_ ), relocation_section( section_ ) { } //------------------------------------------------------------------------------ Elf_Xword get_entries_num() const { Elf_Xword nRet = 0; if ( 0 != relocation_section->get_entry_size() ) { nRet = relocation_section->get_size() / relocation_section->get_entry_size(); } return nRet; } //------------------------------------------------------------------------------ bool get_entry( Elf_Xword index, Elf64_Addr& offset, Elf_Word& symbol, Elf_Word& type, Elf_Sxword& addend ) const { if ( index >= get_entries_num() ) { // Is index valid return false; } if ( elf_file.get_class() == ELFCLASS32 ) { if ( SHT_REL == relocation_section->get_type() ) { generic_get_entry_rel( index, offset, symbol, type, addend ); } else if ( SHT_RELA == relocation_section->get_type() ) { generic_get_entry_rela( index, offset, symbol, type, addend ); } } else { if ( SHT_REL == relocation_section->get_type() ) { generic_get_entry_rel( index, offset, symbol, type, addend ); } else if ( SHT_RELA == relocation_section->get_type() ) { generic_get_entry_rela( index, offset, symbol, type, addend ); } } return true; } //------------------------------------------------------------------------------ bool get_entry( Elf_Xword index, Elf64_Addr& offset, Elf64_Addr& symbolValue, std::string& symbolName, Elf_Word& type, Elf_Sxword& addend, Elf_Sxword& calcValue ) const { // Do regular job Elf_Word symbol; bool ret = get_entry( index, offset, symbol, type, addend ); // Find the symbol Elf_Xword size; unsigned char bind; unsigned char symbolType; Elf_Half section; unsigned char other; symbol_section_accessor symbols( elf_file, elf_file.sections[get_symbol_table_index()] ); ret = ret && symbols.get_symbol( symbol, symbolName, symbolValue, size, bind, symbolType, section, other ); if ( ret ) { // Was it successful? switch ( type ) { case R_386_NONE: // none calcValue = 0; break; case R_386_32: // S + A calcValue = symbolValue + addend; break; case R_386_PC32: // S + A - P calcValue = symbolValue + addend - offset; break; case R_386_GOT32: // G + A - P calcValue = 0; break; case R_386_PLT32: // L + A - P calcValue = 0; break; case R_386_COPY: // none calcValue = 0; break; case R_386_GLOB_DAT: // S case R_386_JMP_SLOT: // S calcValue = symbolValue; break; case R_386_RELATIVE: // B + A calcValue = addend; break; case R_386_GOTOFF: // S + A - GOT calcValue = 0; break; case R_386_GOTPC: // GOT + A - P calcValue = 0; break; default: // Not recognized symbol! calcValue = 0; break; } } return ret; } //------------------------------------------------------------------------------ bool set_entry( Elf_Xword index, Elf64_Addr offset, Elf_Word symbol, Elf_Word type, Elf_Sxword addend ) { if ( index >= get_entries_num() ) { // Is index valid return false; } if ( elf_file.get_class() == ELFCLASS32 ) { if ( SHT_REL == relocation_section->get_type() ) { generic_set_entry_rel( index, offset, symbol, type, addend ); } else if ( SHT_RELA == relocation_section->get_type() ) { generic_set_entry_rela( index, offset, symbol, type, addend ); } } else { if ( SHT_REL == relocation_section->get_type() ) { generic_set_entry_rel( index, offset, symbol, type, addend ); } else if ( SHT_RELA == relocation_section->get_type() ) { generic_set_entry_rela( index, offset, symbol, type, addend ); } } return true; } //------------------------------------------------------------------------------ void add_entry( Elf64_Addr offset, Elf_Xword info ) { if ( elf_file.get_class() == ELFCLASS32 ) { generic_add_entry( offset, info ); } else { generic_add_entry( offset, info ); } } //------------------------------------------------------------------------------ void add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type ) { Elf_Xword info; if ( elf_file.get_class() == ELFCLASS32 ) { info = ELF32_R_INFO( (Elf_Xword)symbol, type ); } else { info = ELF64_R_INFO( (Elf_Xword)symbol, type ); } add_entry( offset, info ); } //------------------------------------------------------------------------------ void add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) { if ( elf_file.get_class() == ELFCLASS32 ) { generic_add_entry( offset, info, addend ); } else { generic_add_entry( offset, info, addend ); } } //------------------------------------------------------------------------------ void add_entry( Elf64_Addr offset, Elf_Word symbol, unsigned char type, Elf_Sxword addend ) { Elf_Xword info; if ( elf_file.get_class() == ELFCLASS32 ) { info = ELF32_R_INFO( (Elf_Xword)symbol, type ); } else { info = ELF64_R_INFO( (Elf_Xword)symbol, type ); } add_entry( offset, info, addend ); } //------------------------------------------------------------------------------ void add_entry( string_section_accessor str_writer, const char* str, symbol_section_accessor sym_writer, Elf64_Addr value, Elf_Word size, unsigned char sym_info, unsigned char other, Elf_Half shndx, Elf64_Addr offset, unsigned char type ) { Elf_Word str_index = str_writer.add_string( str ); Elf_Word sym_index = sym_writer.add_symbol( str_index, value, size, sym_info, other, shndx ); add_entry( offset, sym_index, type ); } //------------------------------------------------------------------------------ void swap_symbols( Elf_Xword first, Elf_Xword second ) { Elf64_Addr offset; Elf_Word symbol; Elf_Word rtype; Elf_Sxword addend; for ( Elf_Word i = 0; i < get_entries_num(); i++ ) { get_entry( i, offset, symbol, rtype, addend ); if ( symbol == first ) { set_entry( i, offset, (Elf_Word)second, rtype, addend ); } if ( symbol == second ) { set_entry( i, offset, (Elf_Word)first, rtype, addend ); } } } //------------------------------------------------------------------------------ private: //------------------------------------------------------------------------------ Elf_Half get_symbol_table_index() const { return (Elf_Half)relocation_section->get_link(); } //------------------------------------------------------------------------------ template void generic_get_entry_rel( Elf_Xword index, Elf64_Addr& offset, Elf_Word& symbol, Elf_Word& type, Elf_Sxword& addend ) const { const endianess_convertor& convertor = elf_file.get_convertor(); const T* pEntry = reinterpret_cast( relocation_section->get_data() + index * relocation_section->get_entry_size() ); offset = convertor( pEntry->r_offset ); Elf_Xword tmp = convertor( pEntry->r_info ); symbol = get_sym_and_type::get_r_sym( tmp ); type = get_sym_and_type::get_r_type( tmp ); addend = 0; } //------------------------------------------------------------------------------ template void generic_get_entry_rela( Elf_Xword index, Elf64_Addr& offset, Elf_Word& symbol, Elf_Word& type, Elf_Sxword& addend ) const { const endianess_convertor& convertor = elf_file.get_convertor(); const T* pEntry = reinterpret_cast( relocation_section->get_data() + index * relocation_section->get_entry_size() ); offset = convertor( pEntry->r_offset ); Elf_Xword tmp = convertor( pEntry->r_info ); symbol = get_sym_and_type::get_r_sym( tmp ); type = get_sym_and_type::get_r_type( tmp ); addend = convertor( pEntry->r_addend ); } //------------------------------------------------------------------------------ template void generic_set_entry_rel( Elf_Xword index, Elf64_Addr offset, Elf_Word symbol, Elf_Word type, Elf_Sxword ) { const endianess_convertor& convertor = elf_file.get_convertor(); T* pEntry = const_cast( reinterpret_cast( relocation_section->get_data() + index * relocation_section->get_entry_size() ) ); if ( elf_file.get_class() == ELFCLASS32 ) { pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type ); } else { pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type ); } pEntry->r_offset = offset; pEntry->r_offset = convertor( pEntry->r_offset ); pEntry->r_info = convertor( pEntry->r_info ); } //------------------------------------------------------------------------------ template void generic_set_entry_rela( Elf_Xword index, Elf64_Addr offset, Elf_Word symbol, Elf_Word type, Elf_Sxword addend ) { const endianess_convertor& convertor = elf_file.get_convertor(); T* pEntry = const_cast( reinterpret_cast( relocation_section->get_data() + index * relocation_section->get_entry_size() ) ); if ( elf_file.get_class() == ELFCLASS32 ) { pEntry->r_info = ELF32_R_INFO( (Elf_Xword)symbol, type ); } else { pEntry->r_info = ELF64_R_INFO( (Elf_Xword)symbol, type ); } pEntry->r_offset = offset; pEntry->r_addend = addend; pEntry->r_offset = convertor( pEntry->r_offset ); pEntry->r_info = convertor( pEntry->r_info ); pEntry->r_addend = convertor( pEntry->r_addend ); } //------------------------------------------------------------------------------ template void generic_add_entry( Elf64_Addr offset, Elf_Xword info ) { const endianess_convertor& convertor = elf_file.get_convertor(); T entry; entry.r_offset = offset; entry.r_info = info; entry.r_offset = convertor( entry.r_offset ); entry.r_info = convertor( entry.r_info ); relocation_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); } //------------------------------------------------------------------------------ template void generic_add_entry( Elf64_Addr offset, Elf_Xword info, Elf_Sxword addend ) { const endianess_convertor& convertor = elf_file.get_convertor(); T entry; entry.r_offset = offset; entry.r_info = info; entry.r_addend = addend; entry.r_offset = convertor( entry.r_offset ); entry.r_info = convertor( entry.r_info ); entry.r_addend = convertor( entry.r_addend ); relocation_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); } //------------------------------------------------------------------------------ private: const elfio& elf_file; S* relocation_section; }; using relocation_section_accessor = relocation_section_accessor_template
; using const_relocation_section_accessor = relocation_section_accessor_template; } // namespace ELFIO #endif // ELFIO_RELOCATION_HPP /*** End of inlined file: elfio_relocation.hpp ***/ /*** Start of inlined file: elfio_dynamic.hpp ***/ #ifndef ELFIO_DYNAMIC_HPP #define ELFIO_DYNAMIC_HPP namespace ELFIO { //------------------------------------------------------------------------------ template class dynamic_section_accessor_template { public: //------------------------------------------------------------------------------ dynamic_section_accessor_template( const elfio& elf_file_, S* section_ ) : elf_file( elf_file_ ), dynamic_section( section_ ) { } //------------------------------------------------------------------------------ Elf_Xword get_entries_num() const { Elf_Xword nRet = 0; if ( 0 != dynamic_section->get_entry_size() ) { nRet = dynamic_section->get_size() / dynamic_section->get_entry_size(); } return nRet; } //------------------------------------------------------------------------------ bool get_entry( Elf_Xword index, Elf_Xword& tag, Elf_Xword& value, std::string& str ) const { if ( index >= get_entries_num() ) { // Is index valid return false; } if ( elf_file.get_class() == ELFCLASS32 ) { generic_get_entry_dyn( index, tag, value ); } else { generic_get_entry_dyn( index, tag, value ); } // If the tag may have a string table reference, prepare the string if ( tag == DT_NEEDED || tag == DT_SONAME || tag == DT_RPATH || tag == DT_RUNPATH ) { string_section_accessor strsec = elf_file.sections[get_string_table_index()]; const char* result = strsec.get_string( value ); if ( 0 == result ) { str.clear(); return false; } str = result; } else { str.clear(); } return true; } //------------------------------------------------------------------------------ void add_entry( Elf_Xword tag, Elf_Xword value ) { if ( elf_file.get_class() == ELFCLASS32 ) { generic_add_entry( tag, value ); } else { generic_add_entry( tag, value ); } } //------------------------------------------------------------------------------ void add_entry( Elf_Xword tag, const std::string& str ) { string_section_accessor strsec = elf_file.sections[get_string_table_index()]; Elf_Xword value = strsec.add_string( str ); add_entry( tag, value ); } //------------------------------------------------------------------------------ private: //------------------------------------------------------------------------------ Elf_Half get_string_table_index() const { return (Elf_Half)dynamic_section->get_link(); } //------------------------------------------------------------------------------ template void generic_get_entry_dyn( Elf_Xword index, Elf_Xword& tag, Elf_Xword& value ) const { const endianess_convertor& convertor = elf_file.get_convertor(); // Check unusual case when dynamic section has no data if ( dynamic_section->get_data() == 0 || ( index + 1 ) * dynamic_section->get_entry_size() > dynamic_section->get_size() ) { tag = DT_NULL; value = 0; return; } const T* pEntry = reinterpret_cast( dynamic_section->get_data() + index * dynamic_section->get_entry_size() ); tag = convertor( pEntry->d_tag ); switch ( tag ) { case DT_NULL: case DT_SYMBOLIC: case DT_TEXTREL: case DT_BIND_NOW: value = 0; break; case DT_NEEDED: case DT_PLTRELSZ: case DT_RELASZ: case DT_RELAENT: case DT_STRSZ: case DT_SYMENT: case DT_SONAME: case DT_RPATH: case DT_RELSZ: case DT_RELENT: case DT_PLTREL: case DT_INIT_ARRAYSZ: case DT_FINI_ARRAYSZ: case DT_RUNPATH: case DT_FLAGS: case DT_PREINIT_ARRAYSZ: value = convertor( pEntry->d_un.d_val ); break; case DT_PLTGOT: case DT_HASH: case DT_STRTAB: case DT_SYMTAB: case DT_RELA: case DT_INIT: case DT_FINI: case DT_REL: case DT_DEBUG: case DT_JMPREL: case DT_INIT_ARRAY: case DT_FINI_ARRAY: case DT_PREINIT_ARRAY: default: value = convertor( pEntry->d_un.d_ptr ); break; } } //------------------------------------------------------------------------------ template void generic_add_entry( Elf_Xword tag, Elf_Xword value ) { const endianess_convertor& convertor = elf_file.get_convertor(); T entry; switch ( tag ) { case DT_NULL: case DT_SYMBOLIC: case DT_TEXTREL: case DT_BIND_NOW: value = 0; case DT_NEEDED: case DT_PLTRELSZ: case DT_RELASZ: case DT_RELAENT: case DT_STRSZ: case DT_SYMENT: case DT_SONAME: case DT_RPATH: case DT_RELSZ: case DT_RELENT: case DT_PLTREL: case DT_INIT_ARRAYSZ: case DT_FINI_ARRAYSZ: case DT_RUNPATH: case DT_FLAGS: case DT_PREINIT_ARRAYSZ: entry.d_un.d_val = convertor( value ); break; case DT_PLTGOT: case DT_HASH: case DT_STRTAB: case DT_SYMTAB: case DT_RELA: case DT_INIT: case DT_FINI: case DT_REL: case DT_DEBUG: case DT_JMPREL: case DT_INIT_ARRAY: case DT_FINI_ARRAY: case DT_PREINIT_ARRAY: default: entry.d_un.d_ptr = convertor( value ); break; } entry.d_tag = convertor( tag ); dynamic_section->append_data( reinterpret_cast( &entry ), sizeof( entry ) ); } //------------------------------------------------------------------------------ private: const elfio& elf_file; S* dynamic_section; }; using dynamic_section_accessor = dynamic_section_accessor_template
; using const_dynamic_section_accessor = dynamic_section_accessor_template; } // namespace ELFIO #endif // ELFIO_DYNAMIC_HPP /*** End of inlined file: elfio_dynamic.hpp ***/ /*** Start of inlined file: elfio_modinfo.hpp ***/ #ifndef ELFIO_MODINFO_HPP #define ELFIO_MODINFO_HPP #include #include namespace ELFIO { //------------------------------------------------------------------------------ template class modinfo_section_accessor_template { public: //------------------------------------------------------------------------------ modinfo_section_accessor_template( S* section_ ) : modinfo_section( section_ ) { process_section(); } //------------------------------------------------------------------------------ Elf_Word get_attribute_num() const { return (Elf_Word)content.size(); } //------------------------------------------------------------------------------ bool get_attribute( Elf_Word no, std::string& field, std::string& value ) const { if ( no < content.size() ) { field = content[no].first; value = content[no].second; return true; } return false; } //------------------------------------------------------------------------------ bool get_attribute( std::string field_name, std::string& value ) const { for ( auto i = content.begin(); i != content.end(); i++ ) { if ( field_name == i->first ) { value = i->second; return true; } } return false; } //------------------------------------------------------------------------------ Elf_Word add_attribute( std::string field, std::string value ) { Elf_Word current_position = 0; if ( modinfo_section ) { // Strings are addeded to the end of the current section data current_position = (Elf_Word)modinfo_section->get_size(); std::string attribute = field + "=" + value; modinfo_section->append_data( attribute + '\0' ); content.push_back( std::pair( field, value ) ); } return current_position; } //------------------------------------------------------------------------------ private: void process_section() { const char* pdata = modinfo_section->get_data(); if ( pdata ) { ELFIO::Elf_Xword i = 0; while ( i < modinfo_section->get_size() ) { while ( i < modinfo_section->get_size() && !pdata[i] ) i++; if ( i < modinfo_section->get_size() ) { std::string info = pdata + i; size_t loc = info.find( '=' ); std::pair attribute( info.substr( 0, loc ), info.substr( loc + 1 ) ); content.push_back( attribute ); i += info.length(); } } } } //------------------------------------------------------------------------------ private: S* modinfo_section; std::vector> content; }; using modinfo_section_accessor = modinfo_section_accessor_template
; using const_modinfo_section_accessor = modinfo_section_accessor_template; } // namespace ELFIO #endif // ELFIO_MODINFO_HPP /*** End of inlined file: elfio_modinfo.hpp ***/ #ifdef _MSC_VER #pragma warning( pop ) #endif #endif // ELFIO_HPP /*** End of inlined file: elfio.hpp ***/ namespace ELFIO { static struct class_table_t { const char key; const char* str; } class_table[] = { { ELFCLASS32, "ELF32" }, { ELFCLASS64, "ELF64" }, }; static struct endian_table_t { const char key; const char* str; } endian_table[] = { { ELFDATANONE, "None" }, { ELFDATA2LSB, "Little endian" }, { ELFDATA2MSB, "Big endian" }, }; static struct version_table_t { const Elf64_Word key; const char* str; } version_table[] = { { EV_NONE, "None" }, { EV_CURRENT, "Current" }, }; static struct type_table_t { const Elf32_Half key; const char* str; } type_table[] = { { ET_NONE, "No file type" }, { ET_REL, "Relocatable file" }, { ET_EXEC, "Executable file" }, { ET_DYN, "Shared object file" }, { ET_CORE, "Core file" }, }; static struct machine_table_t { const Elf64_Half key; const char* str; } machine_table[] = { { EM_NONE, "No machine" }, { EM_M32, "AT&T WE 32100" }, { EM_SPARC, "SUN SPARC" }, { EM_386, "Intel 80386" }, { EM_68K, "Motorola m68k family" }, { EM_88K, "Motorola m88k family" }, { EM_486, "Intel 80486// Reserved for future use" }, { EM_860, "Intel 80860" }, { EM_MIPS, "MIPS R3000 (officially, big-endian only)" }, { EM_S370, "IBM System/370" }, { EM_MIPS_RS3_LE, "MIPS R3000 little-endian (Oct 4 1999 Draft) Deprecated" }, { EM_res011, "Reserved" }, { EM_res012, "Reserved" }, { EM_res013, "Reserved" }, { EM_res014, "Reserved" }, { EM_PARISC, "HPPA" }, { EM_res016, "Reserved" }, { EM_VPP550, "Fujitsu VPP500" }, { EM_SPARC32PLUS, "Sun's v8plus" }, { EM_960, "Intel 80960" }, { EM_PPC, "PowerPC" }, { EM_PPC64, "64-bit PowerPC" }, { EM_S390, "IBM S/390" }, { EM_SPU, "Sony/Toshiba/IBM SPU" }, { EM_res024, "Reserved" }, { EM_res025, "Reserved" }, { EM_res026, "Reserved" }, { EM_res027, "Reserved" }, { EM_res028, "Reserved" }, { EM_res029, "Reserved" }, { EM_res030, "Reserved" }, { EM_res031, "Reserved" }, { EM_res032, "Reserved" }, { EM_res033, "Reserved" }, { EM_res034, "Reserved" }, { EM_res035, "Reserved" }, { EM_V800, "NEC V800 series" }, { EM_FR20, "Fujitsu FR20" }, { EM_RH32, "TRW RH32" }, { EM_MCORE, "Motorola M*Core // May also be taken by Fujitsu MMA" }, { EM_RCE, "Old name for MCore" }, { EM_ARM, "ARM" }, { EM_OLD_ALPHA, "Digital Alpha" }, { EM_SH, "Renesas (formerly Hitachi) / SuperH SH" }, { EM_SPARCV9, "SPARC v9 64-bit" }, { EM_TRICORE, "Siemens Tricore embedded processor" }, { EM_ARC, "ARC Cores" }, { EM_H8_300, "Renesas (formerly Hitachi) H8/300" }, { EM_H8_300H, "Renesas (formerly Hitachi) H8/300H" }, { EM_H8S, "Renesas (formerly Hitachi) H8S" }, { EM_H8_500, "Renesas (formerly Hitachi) H8/500" }, { EM_IA_64, "Intel IA-64 Processor" }, { EM_MIPS_X, "Stanford MIPS-X" }, { EM_COLDFIRE, "Motorola Coldfire" }, { EM_68HC12, "Motorola M68HC12" }, { EM_MMA, "Fujitsu Multimedia Accelerator" }, { EM_PCP, "Siemens PCP" }, { EM_NCPU, "Sony nCPU embedded RISC processor" }, { EM_NDR1, "Denso NDR1 microprocesspr" }, { EM_STARCORE, "Motorola Star*Core processor" }, { EM_ME16, "Toyota ME16 processor" }, { EM_ST100, "STMicroelectronics ST100 processor" }, { EM_TINYJ, "Advanced Logic Corp. TinyJ embedded processor" }, { EM_X86_64, "Advanced Micro Devices X86-64 processor" }, { EM_PDSP, "Sony DSP Processor" }, { EM_PDP10, "Digital Equipment Corp. PDP-10" }, { EM_PDP11, "Digital Equipment Corp. PDP-11" }, { EM_FX66, "Siemens FX66 microcontroller" }, { EM_ST9PLUS, "STMicroelectronics ST9+ 8/16 bit microcontroller" }, { EM_ST7, "STMicroelectronics ST7 8-bit microcontroller" }, { EM_68HC16, "Motorola MC68HC16 Microcontroller" }, { EM_68HC11, "Motorola MC68HC11 Microcontroller" }, { EM_68HC08, "Motorola MC68HC08 Microcontroller" }, { EM_68HC05, "Motorola MC68HC05 Microcontroller" }, { EM_SVX, "Silicon Graphics SVx" }, { EM_ST19, "STMicroelectronics ST19 8-bit cpu" }, { EM_VAX, "Digital VAX" }, { EM_CRIS, "Axis Communications 32-bit embedded processor" }, { EM_JAVELIN, "Infineon Technologies 32-bit embedded cpu" }, { EM_FIREPATH, "Element 14 64-bit DSP processor" }, { EM_ZSP, "LSI Logic's 16-bit DSP processor" }, { EM_MMIX, "Donald Knuth's educational 64-bit processor" }, { EM_HUANY, "Harvard's machine-independent format" }, { EM_PRISM, "SiTera Prism" }, { EM_AVR, "Atmel AVR 8-bit microcontroller" }, { EM_FR30, "Fujitsu FR30" }, { EM_D10V, "Mitsubishi D10V" }, { EM_D30V, "Mitsubishi D30V" }, { EM_V850, "NEC v850" }, { EM_M32R, "Renesas M32R (formerly Mitsubishi M32R)" }, { EM_MN10300, "Matsushita MN10300" }, { EM_MN10200, "Matsushita MN10200" }, { EM_PJ, "picoJava" }, { EM_OPENRISC, "OpenRISC 32-bit embedded processor" }, { EM_ARC_A5, "ARC Cores Tangent-A5" }, { EM_XTENSA, "Tensilica Xtensa Architecture" }, { EM_VIDEOCORE, "Alphamosaic VideoCore processor" }, { EM_TMM_GPP, "Thompson Multimedia General Purpose Processor" }, { EM_NS32K, "National Semiconductor 32000 series" }, { EM_TPC, "Tenor Network TPC processor" }, { EM_SNP1K, "Trebia SNP 1000 processor" }, { EM_ST200, "STMicroelectronics ST200 microcontroller" }, { EM_IP2K, "Ubicom IP2022 micro controller" }, { EM_MAX, "MAX Processor" }, { EM_CR, "National Semiconductor CompactRISC" }, { EM_F2MC16, "Fujitsu F2MC16" }, { EM_MSP430, "TI msp430 micro controller" }, { EM_BLACKFIN, "ADI Blackfin" }, { EM_SE_C33, "S1C33 Family of Seiko Epson processors" }, { EM_SEP, "Sharp embedded microprocessor" }, { EM_ARCA, "Arca RISC Microprocessor" }, { EM_UNICORE, "Microprocessor series from PKU-Unity Ltd. and MPRC of " "Peking University" }, { EM_EXCESS, "eXcess: 16/32/64-bit configurable embedded CPU" }, { EM_DXP, "Icera Semiconductor Inc. Deep Execution Processor" }, { EM_ALTERA_NIOS2, "Altera Nios II soft-core processor" }, { EM_CRX, "National Semiconductor CRX" }, { EM_XGATE, "Motorola XGATE embedded processor" }, { EM_C166, "Infineon C16x/XC16x processor" }, { EM_M16C, "Renesas M16C series microprocessors" }, { EM_DSPIC30F, "Microchip Technology dsPIC30F Digital Signal Controller" }, { EM_CE, "Freescale Communication Engine RISC core" }, { EM_M32C, "Renesas M32C series microprocessors" }, { EM_res121, "Reserved" }, { EM_res122, "Reserved" }, { EM_res123, "Reserved" }, { EM_res124, "Reserved" }, { EM_res125, "Reserved" }, { EM_res126, "Reserved" }, { EM_res127, "Reserved" }, { EM_res128, "Reserved" }, { EM_res129, "Reserved" }, { EM_res130, "Reserved" }, { EM_TSK3000, "Altium TSK3000 core" }, { EM_RS08, "Freescale RS08 embedded processor" }, { EM_res133, "Reserved" }, { EM_ECOG2, "Cyan Technology eCOG2 microprocessor" }, { EM_SCORE, "Sunplus Score" }, { EM_SCORE7, "Sunplus S+core7 RISC processor" }, { EM_DSP24, "New Japan Radio (NJR) 24-bit DSP Processor" }, { EM_VIDEOCORE3, "Broadcom VideoCore III processor" }, { EM_LATTICEMICO32, "RISC processor for Lattice FPGA architecture" }, { EM_SE_C17, "Seiko Epson C17 family" }, { EM_TI_C6000, "Texas Instruments TMS320C6000 DSP family" }, { EM_TI_C2000, "Texas Instruments TMS320C2000 DSP family" }, { EM_TI_C5500, "Texas Instruments TMS320C55x DSP family" }, { EM_res143, "Reserved" }, { EM_res144, "Reserved" }, { EM_res145, "Reserved" }, { EM_res146, "Reserved" }, { EM_res147, "Reserved" }, { EM_res148, "Reserved" }, { EM_res149, "Reserved" }, { EM_res150, "Reserved" }, { EM_res151, "Reserved" }, { EM_res152, "Reserved" }, { EM_res153, "Reserved" }, { EM_res154, "Reserved" }, { EM_res155, "Reserved" }, { EM_res156, "Reserved" }, { EM_res157, "Reserved" }, { EM_res158, "Reserved" }, { EM_res159, "Reserved" }, { EM_MMDSP_PLUS, "STMicroelectronics 64bit VLIW Data Signal Processor" }, { EM_CYPRESS_M8C, "Cypress M8C microprocessor" }, { EM_R32C, "Renesas R32C series microprocessors" }, { EM_TRIMEDIA, "NXP Semiconductors TriMedia architecture family" }, { EM_QDSP6, "QUALCOMM DSP6 Processor" }, { EM_8051, "Intel 8051 and variants" }, { EM_STXP7X, "STMicroelectronics STxP7x family" }, { EM_NDS32, "Andes Technology compact code size embedded RISC processor family" }, { EM_ECOG1, "Cyan Technology eCOG1X family" }, { EM_ECOG1X, "Cyan Technology eCOG1X family" }, { EM_MAXQ30, "Dallas Semiconductor MAXQ30 Core Micro-controllers" }, { EM_XIMO16, "New Japan Radio (NJR) 16-bit DSP Processor" }, { EM_MANIK, "M2000 Reconfigurable RISC Microprocessor" }, { EM_CRAYNV2, "Cray Inc. NV2 vector architecture" }, { EM_RX, "Renesas RX family" }, { EM_METAG, "Imagination Technologies META processor architecture" }, { EM_MCST_ELBRUS, "MCST Elbrus general purpose hardware architecture" }, { EM_ECOG16, "Cyan Technology eCOG16 family" }, { EM_CR16, "National Semiconductor CompactRISC 16-bit processor" }, { EM_ETPU, "Freescale Extended Time Processing Unit" }, { EM_SLE9X, "Infineon Technologies SLE9X core" }, { EM_L1OM, "Intel L1OM" }, { EM_INTEL181, "Reserved by Intel" }, { EM_INTEL182, "Reserved by Intel" }, { EM_res183, "Reserved by ARM" }, { EM_res184, "Reserved by ARM" }, { EM_AVR32, "Atmel Corporation 32-bit microprocessor family" }, { EM_STM8, "STMicroeletronics STM8 8-bit microcontroller" }, { EM_TILE64, "Tilera TILE64 multicore architecture family" }, { EM_TILEPRO, "Tilera TILEPro multicore architecture family" }, { EM_MICROBLAZE, "Xilinx MicroBlaze 32-bit RISC soft processor core" }, { EM_CUDA, "NVIDIA CUDA architecture " }, }; static struct section_type_table_t { const Elf64_Half key; const char* str; } section_type_table[] = { { SHT_NULL, "NULL" }, { SHT_PROGBITS, "PROGBITS" }, { SHT_SYMTAB, "SYMTAB" }, { SHT_STRTAB, "STRTAB" }, { SHT_RELA, "RELA" }, { SHT_HASH, "HASH" }, { SHT_DYNAMIC, "DYNAMIC" }, { SHT_NOTE, "NOTE" }, { SHT_NOBITS, "NOBITS" }, { SHT_REL, "REL" }, { SHT_SHLIB, "SHLIB" }, { SHT_DYNSYM, "DYNSYM" }, { SHT_INIT_ARRAY, "INIT_ARRAY" }, { SHT_FINI_ARRAY, "FINI_ARRAY" }, { SHT_PREINIT_ARRAY, "PREINIT_ARRAY" }, { SHT_GROUP, "GROUP" }, { SHT_SYMTAB_SHNDX, "SYMTAB_SHNDX " }, }; static struct segment_type_table_t { const Elf_Word key; const char* str; } segment_type_table[] = { { PT_NULL, "NULL" }, { PT_LOAD, "LOAD" }, { PT_DYNAMIC, "DYNAMIC" }, { PT_INTERP, "INTERP" }, { PT_NOTE, "NOTE" }, { PT_SHLIB, "SHLIB" }, { PT_PHDR, "PHDR" }, { PT_TLS, "TLS" }, }; static struct segment_flag_table_t { const Elf_Word key; const char* str; } segment_flag_table[] = { { 0, "" }, { 1, "X" }, { 2, "W" }, { 3, "WX" }, { 4, "R" }, { 5, "RX" }, { 6, "RW" }, { 7, "RWX" }, }; static struct symbol_bind_t { const Elf_Word key; const char* str; } symbol_bind_table[] = { { STB_LOCAL, "LOCAL" }, { STB_GLOBAL, "GLOBAL" }, { STB_WEAK, "WEAK" }, { STB_LOOS, "LOOS" }, { STB_HIOS, "HIOS" }, { STB_MULTIDEF, "MULTIDEF" }, { STB_LOPROC, "LOPROC" }, { STB_HIPROC, "HIPROC" }, }; static struct symbol_type_t { const Elf_Word key; const char* str; } symbol_type_table[] = { { STT_NOTYPE, "NOTYPE" }, { STT_OBJECT, "OBJECT" }, { STT_FUNC, "FUNC" }, { STT_SECTION, "SECTION" }, { STT_FILE, "FILE" }, { STT_COMMON, "COMMON" }, { STT_TLS, "TLS" }, { STT_LOOS, "LOOS" }, { STT_HIOS, "HIOS" }, { STT_LOPROC, "LOPROC" }, { STT_HIPROC, "HIPROC" }, }; static struct dynamic_tag_t { const Elf_Word key; const char* str; } dynamic_tag_table[] = { { DT_NULL, "NULL" }, { DT_NEEDED, "NEEDED" }, { DT_PLTRELSZ, "PLTRELSZ" }, { DT_PLTGOT, "PLTGOT" }, { DT_HASH, "HASH" }, { DT_STRTAB, "STRTAB" }, { DT_SYMTAB, "SYMTAB" }, { DT_RELA, "RELA" }, { DT_RELASZ, "RELASZ" }, { DT_RELAENT, "RELAENT" }, { DT_STRSZ, "STRSZ" }, { DT_SYMENT, "SYMENT" }, { DT_INIT, "INIT" }, { DT_FINI, "FINI" }, { DT_SONAME, "SONAME" }, { DT_RPATH, "RPATH" }, { DT_SYMBOLIC, "SYMBOLIC" }, { DT_REL, "REL" }, { DT_RELSZ, "RELSZ" }, { DT_RELENT, "RELENT" }, { DT_PLTREL, "PLTREL" }, { DT_DEBUG, "DEBUG" }, { DT_TEXTREL, "TEXTREL" }, { DT_JMPREL, "JMPREL" }, { DT_BIND_NOW, "BIND_NOW" }, { DT_INIT_ARRAY, "INIT_ARRAY" }, { DT_FINI_ARRAY, "FINI_ARRAY" }, { DT_INIT_ARRAYSZ, "INIT_ARRAYSZ" }, { DT_FINI_ARRAYSZ, "FINI_ARRAYSZ" }, { DT_RUNPATH, "RUNPATH" }, { DT_FLAGS, "FLAGS" }, { DT_ENCODING, "ENCODING" }, { DT_PREINIT_ARRAY, "PREINIT_ARRAY" }, { DT_PREINIT_ARRAYSZ, "PREINIT_ARRAYSZ" }, { DT_MAXPOSTAGS, "MAXPOSTAGS" }, }; static const ELFIO::Elf_Xword MAX_DATA_ENTRIES = 64; //------------------------------------------------------------------------------ class dump { #define DUMP_DEC_FORMAT( width ) \ std::setw( width ) << std::setfill( ' ' ) << std::dec << std::right #define DUMP_HEX_FORMAT( width ) \ std::setw( width ) << std::setfill( '0' ) << std::hex << std::right #define DUMP_STR_FORMAT( width ) \ std::setw( width ) << std::setfill( ' ' ) << std::hex << std::left public: //------------------------------------------------------------------------------ static void header( std::ostream& out, const elfio& reader ) { if ( !reader.get_header_size() ) { return; } out << "ELF Header" << std::endl << std::endl << " Class: " << str_class( reader.get_class() ) << std::endl << " Encoding: " << str_endian( reader.get_encoding() ) << std::endl << " ELFVersion: " << str_version( reader.get_elf_version() ) << std::endl << " Type: " << str_type( reader.get_type() ) << std::endl << " Machine: " << str_machine( reader.get_machine() ) << std::endl << " Version: " << str_version( reader.get_version() ) << std::endl << " Entry: " << "0x" << std::hex << reader.get_entry() << std::endl << " Flags: " << "0x" << std::hex << reader.get_flags() << std::endl << std::endl; } //------------------------------------------------------------------------------ static void section_headers( std::ostream& out, const elfio& reader ) { Elf_Half n = reader.sections.size(); if ( n == 0 ) { return; } out << "Section Headers:" << std::endl; if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit out << "[ Nr ] Type Addr Size ES Flg Lk Inf " "Al Name" << std::endl; } else { // Output for 64-bit out << "[ Nr ] Type Addr Size " " ES Flg" << std::endl << " Lk Inf Al Name" << std::endl; } for ( Elf_Half i = 0; i < n; ++i ) { // For all sections section* sec = reader.sections[i]; section_header( out, i, sec, reader.get_class() ); } out << "Key to Flags: W (write), A (alloc), X (execute)\n\n" << std::endl; } //------------------------------------------------------------------------------ static void section_header( std::ostream& out, Elf_Half no, const section* sec, unsigned char elf_class ) { std::ios_base::fmtflags original_flags = out.flags(); if ( elf_class == ELFCLASS32 ) { // Output for 32-bit out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) << " " << DUMP_HEX_FORMAT( 8 ) << sec->get_address() << " " << DUMP_HEX_FORMAT( 8 ) << sec->get_size() << " " << DUMP_HEX_FORMAT( 2 ) << sec->get_entry_size() << " " << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) << " " << DUMP_HEX_FORMAT( 2 ) << sec->get_link() << " " << DUMP_HEX_FORMAT( 3 ) << sec->get_info() << " " << DUMP_HEX_FORMAT( 2 ) << sec->get_addr_align() << " " << DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " << std::endl; } else { // Output for 64-bit out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " << DUMP_STR_FORMAT( 17 ) << str_section_type( sec->get_type() ) << " " << DUMP_HEX_FORMAT( 16 ) << sec->get_address() << " " << DUMP_HEX_FORMAT( 16 ) << sec->get_size() << " " << DUMP_HEX_FORMAT( 4 ) << sec->get_entry_size() << " " << DUMP_STR_FORMAT( 3 ) << section_flags( sec->get_flags() ) << " " << std::endl << " " << DUMP_HEX_FORMAT( 4 ) << sec->get_link() << " " << DUMP_HEX_FORMAT( 4 ) << sec->get_info() << " " << DUMP_HEX_FORMAT( 4 ) << sec->get_addr_align() << " " << DUMP_STR_FORMAT( 17 ) << sec->get_name() << " " << std::endl; } out.flags( original_flags ); return; } //------------------------------------------------------------------------------ static void segment_headers( std::ostream& out, const elfio& reader ) { Elf_Half n = reader.segments.size(); if ( n == 0 ) { return; } out << "Segment headers:" << std::endl; if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit out << "[ Nr ] Type VirtAddr PhysAddr FileSize Mem.Size " "Flags Align" << std::endl; } else { // Output for 64-bit out << "[ Nr ] Type VirtAddr PhysAddr " "Flags" << std::endl << " FileSize Mem.Size " "Align" << std::endl; } for ( Elf_Half i = 0; i < n; ++i ) { segment* seg = reader.segments[i]; segment_header( out, i, seg, reader.get_class() ); } out << std::endl; } //------------------------------------------------------------------------------ static void segment_header( std::ostream& out, Elf_Half no, const segment* seg, unsigned int elf_class ) { std::ios_base::fmtflags original_flags = out.flags(); if ( elf_class == ELFCLASS32 ) { // Output for 32-bit out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) << " " << DUMP_HEX_FORMAT( 8 ) << seg->get_virtual_address() << " " << DUMP_HEX_FORMAT( 8 ) << seg->get_physical_address() << " " << DUMP_HEX_FORMAT( 8 ) << seg->get_file_size() << " " << DUMP_HEX_FORMAT( 8 ) << seg->get_memory_size() << " " << DUMP_STR_FORMAT( 8 ) << str_segment_flag( seg->get_flags() ) << " " << DUMP_HEX_FORMAT( 8 ) << seg->get_align() << " " << std::endl; } else { // Output for 64-bit out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " << DUMP_STR_FORMAT( 14 ) << str_segment_type( seg->get_type() ) << " " << DUMP_HEX_FORMAT( 16 ) << seg->get_virtual_address() << " " << DUMP_HEX_FORMAT( 16 ) << seg->get_physical_address() << " " << DUMP_STR_FORMAT( 16 ) << str_segment_flag( seg->get_flags() ) << " " << std::endl << " " << DUMP_HEX_FORMAT( 16 ) << seg->get_file_size() << " " << DUMP_HEX_FORMAT( 16 ) << seg->get_memory_size() << " " << DUMP_HEX_FORMAT( 16 ) << seg->get_align() << " " << std::endl; } out.flags( original_flags ); } //------------------------------------------------------------------------------ static void symbol_tables( std::ostream& out, const elfio& reader ) { Elf_Half n = reader.sections.size(); for ( Elf_Half i = 0; i < n; ++i ) { // For all sections section* sec = reader.sections[i]; if ( SHT_SYMTAB == sec->get_type() || SHT_DYNSYM == sec->get_type() ) { symbol_section_accessor symbols( reader, sec ); Elf_Xword sym_no = symbols.get_symbols_num(); if ( sym_no > 0 ) { out << "Symbol table (" << sec->get_name() << ")" << std::endl; if ( reader.get_class() == ELFCLASS32 ) { // Output for 32-bit out << "[ Nr ] Value Size Type Bind " "Sect Name" << std::endl; } else { // Output for 64-bit out << "[ Nr ] Value Size Type " " Bind Sect" << std::endl << " Name" << std::endl; } for ( Elf_Xword i = 0; i < sym_no; ++i ) { std::string name; Elf64_Addr value = 0; Elf_Xword size = 0; unsigned char bind = 0; unsigned char type = 0; Elf_Half section = 0; unsigned char other = 0; symbols.get_symbol( i, name, value, size, bind, type, section, other ); symbol_table( out, i, name, value, size, bind, type, section, reader.get_class() ); } out << std::endl; } } } } //------------------------------------------------------------------------------ static void symbol_table( std::ostream& out, Elf_Xword no, std::string& name, Elf64_Addr value, Elf_Xword size, unsigned char bind, unsigned char type, Elf_Half section, unsigned int elf_class ) { std::ios_base::fmtflags original_flags = out.flags(); if ( elf_class == ELFCLASS32 ) { // Output for 32-bit out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " << DUMP_HEX_FORMAT( 8 ) << value << " " << DUMP_HEX_FORMAT( 8 ) << size << " " << DUMP_STR_FORMAT( 7 ) << str_symbol_type( type ) << " " << DUMP_STR_FORMAT( 8 ) << str_symbol_bind( bind ) << " " << DUMP_DEC_FORMAT( 5 ) << section << " " << DUMP_STR_FORMAT( 1 ) << name << " " << std::endl; } else { // Output for 64-bit out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " << DUMP_HEX_FORMAT( 16 ) << value << " " << DUMP_HEX_FORMAT( 16 ) << size << " " << DUMP_STR_FORMAT( 7 ) << str_symbol_type( type ) << " " << DUMP_STR_FORMAT( 8 ) << str_symbol_bind( bind ) << " " << DUMP_DEC_FORMAT( 5 ) << section << " " << std::endl << " " << DUMP_STR_FORMAT( 1 ) << name << " " << std::endl; } out.flags( original_flags ); } //------------------------------------------------------------------------------ static void notes( std::ostream& out, const elfio& reader ) { Elf_Half no = reader.sections.size(); for ( Elf_Half i = 0; i < no; ++i ) { // For all sections section* sec = reader.sections[i]; if ( SHT_NOTE == sec->get_type() ) { // Look at notes note_section_accessor notes( reader, sec ); Elf_Word no_notes = notes.get_notes_num(); if ( no > 0 ) { out << "Note section (" << sec->get_name() << ")" << std::endl << " No Type Name" << std::endl; for ( Elf_Word j = 0; j < no_notes; ++j ) { // For all notes Elf_Word type; std::string name; void* desc; Elf_Word descsz; if ( notes.get_note( j, type, name, desc, descsz ) ) { // 'name' usually contains \0 at the end. Try to fix it name = name.c_str(); note( out, j, type, name ); } } out << std::endl; } } } } //------------------------------------------------------------------------------ static void modinfo( std::ostream& out, const elfio& reader ) { Elf_Half no = reader.sections.size(); for ( Elf_Half i = 0; i < no; ++i ) { // For all sections section* sec = reader.sections[i]; if ( ".modinfo" == sec->get_name() ) { // Look for the section out << "Section .modinfo" << std::endl; const_modinfo_section_accessor modinfo( sec ); for ( Elf_Word i = 0; i < modinfo.get_attribute_num(); i++ ) { std::string field; std::string value; if ( modinfo.get_attribute( i, field, value ) ) { out << " " << std::setw( 20 ) << field << std::setw( 0 ) << " = " << value << std::endl; } } out << std::endl; break; } } } //------------------------------------------------------------------------------ static void note( std::ostream& out, int no, Elf_Word type, const std::string& name ) { out << " [" << DUMP_DEC_FORMAT( 2 ) << no << "] " << DUMP_HEX_FORMAT( 8 ) << type << " " << DUMP_STR_FORMAT( 1 ) << name << std::endl; } //------------------------------------------------------------------------------ static void dynamic_tags( std::ostream& out, const elfio& reader ) { Elf_Half n = reader.sections.size(); for ( Elf_Half i = 0; i < n; ++i ) { // For all sections section* sec = reader.sections[i]; if ( SHT_DYNAMIC == sec->get_type() ) { dynamic_section_accessor dynamic( reader, sec ); Elf_Xword dyn_no = dynamic.get_entries_num(); if ( dyn_no > 0 ) { out << "Dynamic section (" << sec->get_name() << ")" << std::endl; out << "[ Nr ] Tag Name/Value" << std::endl; for ( Elf_Xword i = 0; i < dyn_no; ++i ) { Elf_Xword tag = 0; Elf_Xword value = 0; std::string str; dynamic.get_entry( i, tag, value, str ); dynamic_tag( out, i, tag, value, str, reader.get_class() ); if ( DT_NULL == tag ) { break; } } out << std::endl; } } } } //------------------------------------------------------------------------------ static void dynamic_tag( std::ostream& out, Elf_Xword no, Elf_Xword tag, Elf_Xword value, std::string str, unsigned int /*elf_class*/ ) { out << "[" << DUMP_DEC_FORMAT( 5 ) << no << "] " << DUMP_STR_FORMAT( 16 ) << str_dynamic_tag( tag ) << " "; if ( str.empty() ) { out << DUMP_HEX_FORMAT( 16 ) << value << " "; } else { out << DUMP_STR_FORMAT( 32 ) << str << " "; } out << std::endl; } //------------------------------------------------------------------------------ static void section_data( std::ostream& out, const section* sec ) { std::ios_base::fmtflags original_flags = out.flags(); out << sec->get_name() << std::endl; const char* pdata = sec->get_data(); if ( pdata ) { ELFIO::Elf_Xword i; for ( i = 0; i < std::min( sec->get_size(), MAX_DATA_ENTRIES ); ++i ) { if ( i % 16 == 0 ) { out << "[" << DUMP_HEX_FORMAT( 8 ) << i << "]"; } out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF ); if ( i % 16 == 15 ) { out << std::endl; } } if ( i % 16 != 0 ) { out << std::endl; } out.flags( original_flags ); } return; } //------------------------------------------------------------------------------ static void section_datas( std::ostream& out, const elfio& reader ) { Elf_Half n = reader.sections.size(); if ( n == 0 ) { return; } out << "Section Data:" << std::endl; for ( Elf_Half i = 1; i < n; ++i ) { // For all sections section* sec = reader.sections[i]; if ( sec->get_type() == SHT_NOBITS ) { continue; } section_data( out, sec ); } out << std::endl; } //------------------------------------------------------------------------------ static void segment_data( std::ostream& out, Elf_Half no, const segment* seg ) { std::ios_base::fmtflags original_flags = out.flags(); out << "Segment # " << no << std::endl; const char* pdata = seg->get_data(); if ( pdata ) { ELFIO::Elf_Xword i; for ( i = 0; i < std::min( seg->get_file_size(), MAX_DATA_ENTRIES ); ++i ) { if ( i % 16 == 0 ) { out << "[" << DUMP_HEX_FORMAT( 8 ) << i << "]"; } out << " " << DUMP_HEX_FORMAT( 2 ) << ( pdata[i] & 0x000000FF ); if ( i % 16 == 15 ) { out << std::endl; } } if ( i % 16 != 0 ) { out << std::endl; } out.flags( original_flags ); } return; } //------------------------------------------------------------------------------ static void segment_datas( std::ostream& out, const elfio& reader ) { Elf_Half n = reader.segments.size(); if ( n == 0 ) { return; } out << "Segment Data:" << std::endl; for ( Elf_Half i = 0; i < n; ++i ) { // For all sections segment* seg = reader.segments[i]; segment_data( out, i, seg ); } out << std::endl; } private: //------------------------------------------------------------------------------ template std::string static find_value_in_table( const T& table, const K& key ) { std::string res = "?"; for ( unsigned int i = 0; i < sizeof( table ) / sizeof( table[0] ); ++i ) { if ( table[i].key == key ) { res = table[i].str; break; } } return res; } //------------------------------------------------------------------------------ template static std::string format_assoc( const T& table, const K& key ) { std::string str = find_value_in_table( table, key ); if ( str == "?" ) { std::ostringstream oss; oss << str << " (0x" << std::hex << key << ")"; str = oss.str(); } return str; } //------------------------------------------------------------------------------ template static std::string format_assoc( const T& table, const char key ) { return format_assoc( table, (const int)key ); } //------------------------------------------------------------------------------ static std::string section_flags( Elf_Xword flags ) { std::string ret = ""; if ( flags & SHF_WRITE ) { ret += "W"; } if ( flags & SHF_ALLOC ) { ret += "A"; } if ( flags & SHF_EXECINSTR ) { ret += "X"; } return ret; } //------------------------------------------------------------------------------ #define STR_FUNC_TABLE( name ) \ template static std::string str_##name( const T key ) \ { \ return format_assoc( name##_table, key ); \ } STR_FUNC_TABLE( class ) STR_FUNC_TABLE( endian ) STR_FUNC_TABLE( version ) STR_FUNC_TABLE( type ) STR_FUNC_TABLE( machine ) STR_FUNC_TABLE( section_type ) STR_FUNC_TABLE( segment_type ) STR_FUNC_TABLE( segment_flag ) STR_FUNC_TABLE( symbol_bind ) STR_FUNC_TABLE( symbol_type ) STR_FUNC_TABLE( dynamic_tag ) #undef STR_FUNC_TABLE #undef DUMP_DEC_FORMAT #undef DUMP_HEX_FORMAT #undef DUMP_STR_FORMAT }; // class dump }; // namespace ELFIO #endif // ELFIO_DUMP_HPP /*** End of inlined file: elfio_dump.hpp ***/ ukui-interface/tests/kt-test-utils/cpp-stub/stub.h0000664000175000017500000002340715167726076021220 0ustar fengfeng#ifndef __STUB_H__ #define __STUB_H__ #ifdef _WIN32 //windows #include #include #else //linux #include #include #include #endif //c #include #include //c++ #include #define ADDR(CLASS_NAME,MEMBER_NAME) (&CLASS_NAME::MEMBER_NAME) /********************************************************** replace function **********************************************************/ #ifdef _WIN32 #define CACHEFLUSH(addr, size) FlushInstructionCache(GetCurrentProcess(), addr, size) #else #define CACHEFLUSH(addr, size) __builtin___clear_cache(addr, addr + size) #endif #if defined(__aarch64__) || defined(_M_ARM64) #define CODESIZE 16U #define CODESIZE_MIN 16U #define CODESIZE_MAX CODESIZE // ldr x9, +8 // br x9 // addr #define REPLACE_FAR(t, fn, fn_stub)\ ((uint32_t*)fn)[0] = 0x58000040 | 9;\ ((uint32_t*)fn)[1] = 0xd61f0120 | (9 << 5);\ *(long long *)(fn + 8) = (long long )fn_stub;\ CACHEFLUSH((char *)fn, CODESIZE); #define REPLACE_NEAR(t, fn, fn_stub) REPLACE_FAR(t, fn, fn_stub) #elif defined(__arm__) || defined(_M_ARM) #define CODESIZE 8U #define CODESIZE_MIN 8U #define CODESIZE_MAX CODESIZE // ldr pc, [pc, #-4] #define REPLACE_FAR(t, fn, fn_stub)\ ((uint32_t*)fn)[0] = 0xe51ff004;\ ((uint32_t*)fn)[1] = (uint32_t)fn_stub;\ CACHEFLUSH((char *)fn, CODESIZE); #define REPLACE_NEAR(t, fn, fn_stub) REPLACE_FAR(t, fn, fn_stub) #elif defined(__mips64) #define CACHEFLUSH(addr, size) __builtin___clear_cache(addr, addr + size) #define CODESIZE 80U #define CODESIZE_MIN 80U #define CODESIZE_MAX CODESIZE //mips没有PC指针,所以需要手动入栈出栈 //120000ce0: 67bdffe0 daddiu sp, sp, -32 //入栈 //120000ce4: ffbf0018 sd ra, 24(sp) //120000ce8: ffbe0010 sd s8, 16(sp) //120000cec: ffbc0008 sd gp, 8(sp) //120000cf0: 03a0f025 move s8, sp //120000d2c: 03c0e825 move sp, s8 //出栈 //120000d30: dfbf0018 ld ra, 24(sp) //120000d34: dfbe0010 ld s8, 16(sp) //120000d38: dfbc0008 ld gp, 8(sp) //120000d3c: 67bd0020 daddiu sp, sp, 32 //120000d40: 03e00008 jr ra #define REPLACE_FAR(t, fn, fn_stub)\ ((uint32_t *)fn)[0] = 0x67bdffe0;\ ((uint32_t *)fn)[1] = 0xffbf0018;\ ((uint32_t *)fn)[2] = 0xffbe0010;\ ((uint32_t *)fn)[3] = 0xffbc0008;\ ((uint32_t *)fn)[4] = 0x03a0f025;\ *(uint16_t *)(fn + 20) = (long long)fn_stub >> 32;\ *(fn + 22) = 0x19;\ *(fn + 23) = 0x24;\ ((uint32_t *)fn)[6] = 0x0019cc38;\ *(uint16_t *)(fn + 28) = (long long)fn_stub >> 16;\ *(fn + 30) = 0x39;\ *(fn + 31) = 0x37;\ ((uint32_t *)fn)[8] = 0x0019cc38;\ *(uint16_t *)(fn + 36) = (long long)fn_stub;\ *(fn + 38) = 0x39;\ *(fn + 39) = 0x37;\ ((uint32_t *)fn)[10] = 0x0320f809;\ ((uint32_t *)fn)[11] = 0x00000000;\ ((uint32_t *)fn)[12] = 0x00000000;\ ((uint32_t *)fn)[13] = 0x03c0e825;\ ((uint32_t *)fn)[14] = 0xdfbf0018;\ ((uint32_t *)fn)[15] = 0xdfbe0010;\ ((uint32_t *)fn)[16] = 0xdfbc0008;\ ((uint32_t *)fn)[17] = 0x67bd0020;\ ((uint32_t *)fn)[18] = 0x03e00008;\ ((uint32_t *)fn)[19] = 0x00000000;\ CACHEFLUSH((char *)fn, CODESIZE); #define REPLACE_NEAR(t, fn, fn_stub) REPLACE_FAR(t, fn, fn_stub) #elif defined(__thumb__) || defined(_M_THUMB) #error "Thumb is not supported" #else //__i386__ _x86_64__ #define CODESIZE 13U #define CODESIZE_MIN 5U #define CODESIZE_MAX CODESIZE //13 byte(jmp m16:64) //movabs $0x102030405060708,%r11 //jmpq *%r11 static void REPLACE_FAR(void *t, char *fn, char *fn_stub) { *fn = 0x49; *(fn + 1) = 0xbb; *(long long *)(fn + 2) = (long long)fn_stub; *(fn + 10) = 0x41; *(fn + 11) = 0xff; *(fn + 12) = 0xe3; CACHEFLUSH((char *)fn, CODESIZE); } //5 byte(jmp rel32) #define REPLACE_NEAR(t, fn, fn_stub)\ *fn = 0xE9;\ *(int *)(fn + 1) = (int)(fn_stub - fn - CODESIZE_MIN);\ CACHEFLUSH((char *)fn, CODESIZE); #endif struct func_stub { char *fn; unsigned char code_buf[CODESIZE]; bool far_jmp; }; class Stub { public: Stub() { #ifdef _WIN32 SYSTEM_INFO sys_info; GetSystemInfo(&sys_info); m_pagesize = sys_info.dwPageSize; #else m_pagesize = sysconf(_SC_PAGE_SIZE); #endif if (m_pagesize < 0) { m_pagesize = 4096; } } ~Stub() { clear(); } virtual void clear() { std::map::iterator iter; struct func_stub *pstub; for(iter=m_result.begin(); iter != m_result.end(); iter++) { pstub = iter->second; #ifdef _WIN32 DWORD lpflOldProtect; if(0 != VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READWRITE, &lpflOldProtect)) #else if (0 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_WRITE | PROT_EXEC)) #endif { if(pstub->far_jmp) { std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MAX); } else { std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MIN); } #ifdef _WIN32 VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READ, &lpflOldProtect); #else CACHEFLUSH(pstub->fn,CODESIZE); mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_EXEC); #endif } iter->second = NULL; delete pstub; } m_result.clear(); return; } template bool set(T addr, S addr_stub) { char * fn; char * fn_stub; fn = addrof(addr); fn_stub = addrof(addr_stub); struct func_stub *pstub; std::map::iterator iter = m_result.find(fn); if (iter == m_result.end()) { pstub = new func_stub; //start pstub->fn = fn; if(distanceof(fn, fn_stub)) { pstub->far_jmp = true; std::memcpy(pstub->code_buf, fn, CODESIZE_MAX); } else { pstub->far_jmp = false; std::memcpy(pstub->code_buf, fn, CODESIZE_MIN); } } else { pstub = iter->second; pstub->far_jmp = distanceof(fn, fn_stub); } #ifdef _WIN32 DWORD lpflOldProtect; if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READWRITE, &lpflOldProtect)) #else if (-1 == mprotect(pageof(pstub->fn), static_cast(m_pagesize * 2), PROT_READ | PROT_WRITE | PROT_EXEC)) #endif { throw("stub set memory protect to w+r+x faild"); return false; } if(pstub->far_jmp) { REPLACE_FAR(this, fn, fn_stub); } else { REPLACE_NEAR(this, fn, fn_stub); } #ifdef _WIN32 if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READ, &lpflOldProtect)) #else if (-1 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_EXEC)) #endif { throw("stub set memory protect to r+x failed"); return false; } m_result.insert(std::pair(fn,pstub)); return true; } template bool reset(T addr) { char * fn; fn = addrof(addr); std::map::iterator iter = m_result.find(fn); if (iter == m_result.end()) { return true; } struct func_stub *pstub; pstub = iter->second; #ifdef _WIN32 DWORD lpflOldProtect; if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READWRITE, &lpflOldProtect)) #else if (-1 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_WRITE | PROT_EXEC)) #endif { throw("stub reset memory protect to w+r+x faild"); return false; } if(pstub->far_jmp) { std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MAX); } else { std::memcpy(pstub->fn, pstub->code_buf, CODESIZE_MIN); } #ifdef _WIN32 if(0 == VirtualProtect(pageof(pstub->fn), m_pagesize * 2, PAGE_EXECUTE_READ, &lpflOldProtect)) #else CACHEFLUSH(pstub->fn,CODESIZE); if (-1 == mprotect(pageof(pstub->fn), m_pagesize * 2, PROT_READ | PROT_EXEC)) #endif { throw("stub reset memory protect to r+x failed"); return false; } m_result.erase(iter); delete pstub; return true; } protected: char *pageof(char* addr) { #ifdef _WIN32 return (char *)((unsigned long long)addr & ~(m_pagesize - 1)); #else return (char *)((unsigned long)addr & ~(m_pagesize - 1)); #endif } template char* addrof(T addr) { union { T _s; char* _d; }ut; ut._s = addr; return ut._d; } bool distanceof(char* addr, char* addr_stub) { std::ptrdiff_t diff = addr_stub >= addr ? addr_stub - addr : addr - addr_stub; if((sizeof(addr) > 4) && (((diff >> 31) - 1) > 0)) { return true; } return false; } protected: #ifdef _WIN32 //LLP64 long long m_pagesize; #else //LP64 long m_pagesize; #endif std::map m_result; }; #endif ukui-interface/tests/kt-test-utils/cpp-stub-ext/0000775000175000017500000000000015167726076020662 5ustar fengfengukui-interface/tests/kt-test-utils/cpp-stub-ext/stubext.h0000664000175000017500000000734115167726076022536 0ustar fengfeng #ifndef STUBEXT_H #define STUBEXT_H /* * Author: Zhang Yu * Maintainer: Zhang Yu * * MIT License * * Copyright (c) 2020 Zhang Yu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ //需修改Stub的私用成员函数和成员变量为保护类型 #include "stub.h" #include "stub-shadow.h" #ifdef DEBUG_STUB_INVOKE // use to make sure the stub function is invoked. # define __DBG_STUB_INVOKE__ printf("stub at %s:%d is invoked.\n", __FILE__, __LINE__); #else # define __DBG_STUB_INVOKE__ #endif #define VADDR(CLASS_NAME, MEMBER_NAME) (typename stub_ext::VFLocator::Func)(&CLASS_NAME::MEMBER_NAME) namespace stub_ext { class StubExt : public Stub { public: StubExt() : Stub() { } template bool set_lamda(T addr, Lamda lamda) { char *fn = addrof(addr); if (m_result.find(fn) != m_result.end()) reset(addr); Wrapper *wrapper = nullptr; auto addr_stub = depictShadow(&wrapper, addr, lamda); if (set(addr, addr_stub)) { m_wrappers.insert(std::make_pair(fn, wrapper)); return true; } else { freeWrapper(wrapper); } return false; } template void reset(T addr) { Stub::reset(addr); char *fn = addrof(addr); auto iter = m_wrappers.find(fn); if (iter != m_wrappers.end()) { freeWrapper(iter->second); m_wrappers.erase(iter); } } ~StubExt() { clear(); } void clear() override { Stub::clear(); for (auto iter = m_wrappers.begin(); iter != m_wrappers.end(); ++iter) { freeWrapper(iter->second); } m_wrappers.clear(); } template static void *get_ctor_addr(bool start = true) { // the start vairable must be true, or the compiler will optimize out. if (start) goto Start; Call_Constructor: // This line of code will not be executed. // The purpose of the code is to allow the compiler to generate the assembly code that calls the constructor. T(); Start: // The address of the line of code T() obtained by assembly char *p = (char *)&&Call_Constructor; // https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html // CALL rel32 void *ret = 0; char pos; char call = 0xe8; do { pos = *p; if (pos == call) { ret = p + 5 + (*(int *)(p + 1)); } } while (!ret && (++p)); return ret; } protected: std::map m_wrappers; }; } #endif // STUBEXT_H ukui-interface/tests/kt-test-utils/cpp-stub-ext/stub-shadow.cpp0000664000175000017500000000314715167726076023633 0ustar fengfeng/* * Author: Zhang Yu * Maintainer: Zhang Yu * * MIT License * * Copyright (c) 2020 Zhang Yu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include "stub-shadow.h" namespace stub_ext { WrapperMap stub_wrappers; Wrapper::Wrapper() { } Wrapper::~Wrapper() { } void freeWrapper(Wrapper *wrapper) { if (!wrapper) return; for (auto iter = stub_wrappers.begin(); iter != stub_wrappers.end();) { if (iter->second == wrapper) iter = stub_wrappers.erase(iter); else ++iter; } delete wrapper; } } ukui-interface/tests/kt-test-utils/cpp-stub-ext/stub-shadow.h0000664000175000017500000001143415167726076023276 0ustar fengfeng #ifndef STUBSHADOW_H #define STUBSHADOW_H /* * Author: Zhang Yu * Maintainer: Zhang Yu * * MIT License * * Copyright (c) 2020 Zhang Yu * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include namespace stub_ext { #define LAMDA_FUNCTION_TYPE decltype(&Lamda::operator()) class Wrapper { public: Wrapper(); virtual ~Wrapper(); }; typedef std::unordered_map WrapperMap; extern WrapperMap stub_wrappers; template class LamdaWrapper : public Wrapper { public: LamdaWrapper(Lamda func): Wrapper(),_func(func){} ~LamdaWrapper(){} Lamda _func; }; template struct VFLocator { }; template struct VFLocator { typedef Ret (*Func)(Obj*, Args...); }; template struct VFLocator { typedef Ret (*Func)(Obj*, Args...); }; template struct LamdaCaller { }; template struct LamdaCaller { template static Ret call(LamdaWrapper *wrapper, OrgArgs&&... args) { return wrapper->_func(std::forward(args)...); } }; template struct LamdaCaller { template static Ret call(LamdaWrapper *wrapper, OrgArgs&&... args) { return wrapper->_func(); } }; template struct FuncShadow { }; template struct FuncShadow { typedef Ret (*Shadow)(Args...); typedef Ret RetType; static Ret call(Args ...args) { Shadow shadow = &call; long id = (long)shadow; auto iter = stub_wrappers.find(id); assert(stub_wrappers.find(id) != stub_wrappers.end()); LamdaWrapper *wrapper = dynamic_cast *>(iter->second); return LamdaCaller::call(wrapper, args...); } }; template struct FuncShadow { typedef Ret (*Shadow)(Obj *,Args...); typedef Ret RetType; static Ret call(Obj *obj, Args ...args) { Shadow shadow = &call; long id = (long)shadow; auto iter = stub_wrappers.find(id); assert(stub_wrappers.find(id) != stub_wrappers.end()); LamdaWrapper *wrapper = dynamic_cast *>(iter->second); return LamdaCaller::call(wrapper, obj, args...); } }; template struct FuncShadow { typedef Ret (*Shadow)(Obj *,Args...); typedef Ret RetType; static Ret call(Obj *obj, Args ...args) { Shadow shadow = &call; long id = (long)shadow; auto iter = stub_wrappers.find(id); assert(stub_wrappers.find(id) != stub_wrappers.end()); LamdaWrapper *wrapper = dynamic_cast *>(iter->second); return LamdaCaller::call(wrapper, obj, args...); } }; template typename FuncShadow::Shadow depictShadow(Wrapper **wrapper, Func func, Lamda lamda) { *wrapper = new LamdaWrapper(lamda); typename FuncShadow::Shadow shadow = &FuncShadow::call; long id = (long)shadow; assert(stub_wrappers.find(id) == stub_wrappers.end()); stub_wrappers.insert(std::make_pair(id,*wrapper)); return shadow; } void freeWrapper(Wrapper *wrapper); } #endif // STUBSHADOW_H ukui-interface/tests/unit_test_log4qt/0000775000175000017500000000000015167726076017106 5ustar fengfengukui-interface/tests/unit_test_log4qt/main.cpp0000664000175000017500000000146315167726076020542 0ustar fengfeng/* * Copyright (C) 2025 KylinSoft Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-interface/tests/unit_test_log4qt/unit_test_log4qt.cpp0000664000175000017500000016136215167726076023133 0ustar fengfeng/* * Copyright (C) 2025 KylinSoft Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include "ukui-log4qt.h" #include "ukui-logconfigurator.h" #include "ukui-logmacros.h" #include "ukui-logrolling.h" #include "../../src/log4qt/log4qt/propertyconfigurator.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../src/log4qt/log4qt/helpers/properties.h" #include "../../src/log4qt/log4qt/logger.h" #include "../../src/log4qt/log4qt/varia/listappender.h" #include "../../src/log4qt/log4qt/varia/debugappender.h" #include "../../src/log4qt/log4qt/varia/nullappender.h" #include "../../src/log4qt/log4qt/basicconfigurator.h" #include "../../src/log4qt/log4qt/consoleappender.h" #include "../../src/log4qt/log4qt/dailyrollingfileappender.h" #include "../../src/log4qt/log4qt/fileappender.h" #include "../../src/log4qt/log4qt/helpers/configuratorhelper.h" #include "../../src/log4qt/log4qt/helpers/datetime.h" #include "../../src/log4qt/log4qt/helpers/factory.h" #include "../../src/log4qt/log4qt/helpers/initialisationhelper.h" #include "../../src/log4qt/log4qt/helpers/optionconverter.h" #include "../../src/log4qt/log4qt/helpers/patternformatter.h" #include "../../src/log4qt/log4qt/helpers/properties.h" #include "../../src/log4qt/log4qt/helpers/logerror.h" #include "../../src/log4qt/log4qt/logmanager.h" #include "../../src/log4qt/log4qt/loggerrepository.h" #include "../../src/log4qt/log4qt/patternlayout.h" #include "../../src/log4qt/log4qt/propertyconfigurator.h" #include "../../src/log4qt/log4qt/rollingfileappender.h" #include "../../src/log4qt/log4qt/simplelayout.h" #include "../../src/log4qt/log4qt/ttcclayout.h" #include "../../src/log4qt/log4qt/varia/denyallfilter.h" #include "../../src/log4qt/log4qt/varia/levelmatchfilter.h" #include "../../src/log4qt/log4qt/varia/levelrangefilter.h" #include "../../src/log4qt/log4qt/varia/stringmatchfilter.h" using namespace Log4Qt; // 辅助函数,用于检查日志输出(在实际测试中可能需要更复杂的逻辑来捕获和验证日志输出) void CheckLogOutput(const QString &expected) { // 注意:这里只是一个占位符,实际实现需要捕获日志输出并进行比较 // 例如,可以使用重定向输出流或使用日志框架提供的API来获取日志内容 // 由于示例代码中没有提供这些功能,因此这里仅作为示意 EXPECT_EQ(QString("Dummy log output for testing"), expected); // 需要替换为实际的日志捕获和比较逻辑 } // 测试 initUkuiLog4qt 函数 TEST(UkuiLog4qtTest, TestInit) { QString appName = "test-app"; int result = initUkuiLog4qt(appName); EXPECT_NE(result, -1); // 假设非-1表示成功初始化 // 可以通过检查日志配置或输出进一步验证初始化是否成功 // 例如,检查日志文件是否被创建或日志输出是否符合预期 // 这里使用CheckLogOutput作为示意,但实际实现需要调整 CheckLogOutput("Expected log output after initialization"); } // 测试日志宏 TEST(UkuiLog4qtTest, TestLogMacros) { // 初始化日志系统(在实际测试中,这个初始化可能已经在测试框架的setup函数中完成) initUkuiLog4qt("test-app-for-macros"); // 使用日志宏记录不同级别的日志 KyDebug("This is a debug message"); KyInfo("This is an info message"); KyWarning("This is a warning message"); KyCritical("This is a critical message"); // KyFatal("This is a fatal message"); } // Global variables for testing QTemporaryDir *tempDir = nullptr; // 当前属性列表 Log4Qt::Properties g_log4qtProperties; // Test fixture for UKUI log system class UkuiLogTest : public ::testing::Test { protected: static void SetUpTestSuite() { // Initialize temporary directory for log files tempDir = new QTemporaryDir(); ASSERT_TRUE(tempDir->isValid()); // Initialize UKUI log system UkuiLog4qtConfig::instance()->init("testapp"); } static void TearDownTestSuite() { // Cleanup delete tempDir; UkuiLog4qtConfig::instance()->shutdown(); } }; TEST_F(UkuiLogTest, InitializeLogSystem) { // Verify that log system is initialized correctly ASSERT_TRUE(UkuiLog4qtConfig::instance()->m_isInited); } TEST_F(UkuiLogTest, ConfigureLogProperties) { // Verify that properties are applied correctly Log4Qt::Properties properties; Log4Qt::PropertyConfigurator::configure(properties); EXPECT_EQ(properties.property("log4j.threshold"), "DEBUG"); EXPECT_EQ(properties.property("log4j.rootLogger"), "DEBUG,daily"); EXPECT_EQ(properties.property("ukui.log.dailyDatePattern"), ".yyyy-MM-dd"); } TEST_F(UkuiLogTest, LogFileRolling) { // Configure log rolling with a temporary directory QString logFilePath = tempDir->path() + "/test.log"; UkuiLog4qtRolling roller(logFilePath, 3, 1024 * 1024, 60 * 1000); // 3 files, 1MB each, check every minute roller.start(); // Simulate log file creation and growth QFile file(logFilePath); for (int i = 0; i < 4; ++i) { file.open(QIODevice::WriteOnly | QIODevice::Append); file.write(QByteArray("a").repeated(1024 * 1024)); // Write 1MB file.close(); // Sleep for a short duration to simulate time passing (not necessary in this simplified test) QThread::sleep(1); } // Stop the roller and verify the number of rolled files roller.stop(); roller.wait(); QDir dir(tempDir->path()); QStringList filters; filters << "test.log.*"; dir.setNameFilters(filters); QList fileList = dir.entryInfoList(QDir::Files); // Expect 3 rolled files (test.log.0, test.log.1, test.log.2) and the current test.log EXPECT_EQ(fileList.size(), 4); } // 用于测试的辅助函数 QString createTempFile(const QString &dirPath, const QString &baseName = "testlog") { QFile file(dirPath + "/" + baseName + ".log"); if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { QTextStream out(&file); out << "This is a test log file." << Qt::endl; file.close(); } return file.fileName(); } // 测试类 class UkuiLog4qtRollingTest : public ::testing::Test { protected: static void SetUpTestSuite() { tempDir.setAutoRemove(true); baseFilePath = tempDir.path() + "/testlog.log"; createTempFile(tempDir.path()); // 创建一个初始日志文件 rolling = new UkuiLog4qtRolling(baseFilePath, 3, 1, 1, nullptr); // 最大文件数3,最大文件大小1MB,检查间隔1秒 } static void TearDownTestSuite() { rolling->stop(); rolling->wait(); delete rolling; } static QTemporaryDir tempDir; static QString baseFilePath; static UkuiLog4qtRolling *rolling; }; QTemporaryDir UkuiLog4qtRollingTest::tempDir; QString UkuiLog4qtRollingTest::baseFilePath = ""; UkuiLog4qtRolling *UkuiLog4qtRollingTest::rolling = nullptr; TEST_F(UkuiLog4qtRollingTest, TestFileCountLimit) { // 创建超过最大文件数的日志文件 for (int i = 1; i <= 5; ++i) { createTempFile(tempDir.path(), QString("testlog_%1").arg(i)); } // 启动滚动检查 rolling->start(); QThread::sleep(2); // 等待足够的时间让检查完成 // 验证文件数量 QDir dir(tempDir.path()); dir.setFilter(QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot); QFileInfoList fileList = dir.entryInfoList(); EXPECT_EQ(fileList.count(), 4); // 应该只保留4个文件(包括初始的testlog.log和新创建的3个) } TEST_F(UkuiLog4qtRollingTest, TestFileSizeLimit) { // 创建一个超过最大文件大小的日志文件 QFile file(baseFilePath); if (file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text)) { QTextStream out(&file); for (int i = 0; i < 1024 * 1024 / 20; ++i) { // 大约1MB的内容 out << "This is a line to exceed the size limit." << Qt::endl; } file.close(); } // 启动滚动检查 rolling->start(); QThread::sleep(2); // 等待足够的时间让检查完成 // 验证文件大小 QFileInfo fileInfo(baseFilePath); EXPECT_LE(fileInfo.size(), quint64(1 * 1024 * 1024)); // 文件大小应该被截断到1MB以内 } TEST_F(UkuiLog4qtRollingTest, TestConfigChange) { // 修改配置并验证重启 rolling->setFileCheckLimit(2, 2 * 1024 * 1024, 1); // 最大文件数2,最大文件大小2MB // 创建超过新限制的日志文件 for (int i = 1; i <= 3; ++i) { createTempFile(tempDir.path(), QString("testlog_%1").arg(i)); } // 启动滚动检查 rolling->start(); QThread::sleep(2); // 等待足够的时间让检查完成 // 验证文件数量 QDir dir(tempDir.path()); dir.setFilter(QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot); QFileInfoList fileList = dir.entryInfoList(); EXPECT_EQ(fileList.count(), 2); // 应该只保留2个文件 } LOG4QT_DECLARE_STATIC_LOGGER(test_logger, Test::TestLog4Qt) // 测试类 class Log4QtTest : public ::testing::Test, public QObject { protected: static void SetUpTestSuite() { mSkipLongTests = false; mpLoggingEvents = 0; mProperties = &mDefaultProperties; // Logging LogManager::resetConfiguration(); LogManager::instance()->loggers(); LogManager::instance()->setThreshold(Level::DEBUG_INT); qDebug() << LogManager::instance()->threshold() << LogManager::instance()->version(); LogManager::instance()->welcome(); qDebug() << *LogManager::instance(); // File system QString name = QDir::tempPath() + "/Log4QtTest_" + QDateTime::currentDateTime().toString("yyyyMMdd_hhmmss"); if (!mTemporaryDirectory.mkdir(name)) FAIL(); mTemporaryDirectory.setPath(name); qDebug() << "Using temporaray directory: " << mTemporaryDirectory.path(); // Appender to track events generated by Log4Qt mpLoggingEvents = new Log4Qt::ListAppender(); mpLoggingEvents->retain(); mpLoggingEvents->setName("Log4QtTest"); mpLoggingEvents->setConfiguratorList(true); resetLogging(); } static void TearDownTestSuite() { LogManager::resetConfiguration(); if (!deleteDirectoryTree(mTemporaryDirectory.path())) FAIL(); mpLoggingEvents->release(); } static void resetLogging() { Log4Qt::Logger *p_logger; // Log4Qt logger p_logger = LogManager::logLogger(); p_logger->setAdditivity(false); p_logger->setLevel(Level::WARN_INT); p_logger->removeAllAppenders(); // Log4QtTest appender p_logger->addAppender(mpLoggingEvents); mpLoggingEvents->clearList(); mpLoggingEvents->clearFilters(); mpLoggingEvents->setThreshold(Level::WARN_INT); // Test logger p_logger = test_logger(); p_logger->setAdditivity(true); p_logger->setLevel(Level::NULL_INT); } static bool deleteDirectoryTree(const QString &rName) { QFileInfo file_info(rName); if (!file_info.exists()) return true; if (file_info.isDir()) { QDir d(rName); QStringList members = d.entryList( QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks | QDir::Hidden, QDir::Name | QDir::DirsFirst); QString member; Q_FOREACH (member, members) if (!deleteDirectoryTree(rName + '/' + member)) return false; if (d.rmdir(rName)) return true; qDebug() << "Unable to remove directory: " << rName; return false; } else { QFile f(rName); if (f.remove()) return true; qDebug() << "Unable to remove file: " << rName << "(" << f.errorString() << ")"; return false; } } bool compareStringLists( const QStringList &rActual, const QStringList &rExpected, const QString &rEntry, const QString &rEntries, QString &rResult) { QString tab(" "); QString eol("\n"); // Generate content string QString content; int i; content += tab + "Actual: " + rEntries + ": " + QString::number(rActual.count()) + eol; for (i = 0; i < rActual.count(); i++) content += tab + tab + '\'' + rActual.at(i) + '\'' + eol; content += tab + "Expected: " + rEntries + ": " + QString::number(rExpected.count()) + eol; for (i = 0; i < rExpected.count(); i++) content += tab + tab + '\'' + rExpected.at(i) + '\'' + eol; // Check count if (rActual.count() != rExpected.count()) { rResult = tab + "Compared " + rEntry + " counts are not the same" + eol; rResult += content; return false; } // Check entries for (i = 0; i < rActual.count(); i++) { if (rActual.at(i) != rExpected.at(i)) { rResult = tab + rEntry + " " + QString::number(i + 1) + " is not the same" + eol; rResult += content; return false; } } rResult.clear(); return true; } bool validateDirContents(const QString &rName, const QStringList &rExpected, QString &rResult) { QDir dir(rName); if (!dir.exists()) { rResult = QString("The dir '%1' does not exist").arg(rName); return false; } QStringList actual = dir.entryList( QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks | QDir::Hidden, QDir::Name | QDir::DirsFirst); if (!compareStringLists(actual, rExpected, "Entry", "Entries", rResult)) { QString error = "The directory contents validation failed.\n '%1'\n%2"; rResult = error.arg(rName, rResult); return false; } return true; } bool validateFileContents(const QString &rName, const QStringList &rExpected, QString &rResult) { QFile file(rName); if (!file.exists()) { rResult = QString("The expected file '%1' does not exist (%2)").arg(rName).arg(file.errorString()); return false; } if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { rResult = QString("The expected file '%1' cannot be opened (%2)").arg(rName).arg(file.errorString()); return false; } QStringList actual; QTextStream textstream(&file); QString line = textstream.readLine(); while (!line.isNull()) { actual << line; line = textstream.readLine(); } if (!compareStringLists(actual, rExpected, "Line", "Lines", rResult)) { QString error = "The file contents validation failed.\n '%1'\n%2"; rResult = error.arg(rName, rResult); return false; } return true; } static QString dailyRollingFileAppenderSuffix(const QDateTime &rDateTime) { QString result("."); result += QString::number(rDateTime.date().year()).rightJustified(4, '0'); result += '-'; result += QString::number(rDateTime.date().month()).rightJustified(2, '0'); result += '-'; result += QString::number(rDateTime.date().day()).rightJustified(2, '0'); result += '-'; result += QString::number(rDateTime.time().hour()).rightJustified(2, '0'); result += '-'; result += QString::number(rDateTime.time().minute()).rightJustified(2, '0'); return QString(result); } QString enumValueToKey(QObject *pObject, const char *pEnumeration, int value) { Q_ASSERT(pObject); Q_ASSERT(!QString(pEnumeration).isEmpty()); int i = pObject->metaObject()->indexOfEnumerator(pEnumeration); Q_ASSERT(i >= 0); QMetaEnum enumerator = pObject->metaObject()->enumerator(i); Q_ASSERT(enumerator.isValid()); QString result = enumerator.valueToKey(value); Q_ASSERT(!result.isNull()); return result; } static bool mSkipLongTests; static QDir mTemporaryDirectory; static Log4Qt::ListAppender *mpLoggingEvents; static Log4Qt::Properties mDefaultProperties; static Log4Qt::Properties mProperties; }; bool Log4QtTest::mSkipLongTests = false; QDir Log4QtTest::mTemporaryDirectory; Log4Qt::ListAppender *Log4QtTest::mpLoggingEvents; Log4Qt::Properties Log4QtTest::mDefaultProperties; Log4Qt::Properties Log4QtTest::mProperties; TEST_F(Log4QtTest, DateTime_compability) { QDateTime reference = QDateTime(QDate(2001, 9, 7), QTime(15, 7, 5, 9)); QDateTime q_date_time(reference); DateTime date_time(reference); EXPECT_EQ(date_time.toString("YYYY-MM-ddTHH:mm:ss"), q_date_time.toString("YYYY-MM-ddTHH:mm:ss")); EXPECT_EQ(date_time.toString("dd MMM yyyy HH:mm:ss.zzz"), q_date_time.toString("dd MMM yyyy HH:mm:ss.zzz")); } TEST_F(Log4QtTest, DateTime_week) { qInfo() << "-------------------------0"; EXPECT_EQ(static_cast(QDateTime(QDate(2001, 2, 9), QTime(15, 7, 5, 9))).toString("w"), "6"); qInfo() << "-------------------------1"; EXPECT_EQ(static_cast(QDateTime(QDate(2001, 2, 9), QTime(15, 7, 5, 9))).toString("ww"), "06"); EXPECT_EQ(static_cast(QDateTime(QDate(2001, 9, 7), QTime(15, 7, 5, 9))).toString("w"), "36"); qInfo() << "-------------------------2"; } TEST_F(Log4QtTest, DateTime_milliseconds) { qInfo() << "-------------------------3"; EXPECT_EQ( DateTime(QDateTime(QDate(2001, 9, 7), QTime(15, 7, 5, 9), Qt::UTC)).toMilliSeconds(), Q_INT64_C(999875225009)); qInfo() << "-------------------------4"; EXPECT_EQ( DateTime::fromMilliSeconds(Q_INT64_C(999875225009)).toUTC(), QDateTime(QDate(2001, 9, 7), QTime(15, 7, 5, 9), Qt::UTC)); qInfo() << "-------------------------5"; } TEST_F(Log4QtTest, PatternFormatter) { QString eol; #ifdef Q_OS_WIN32 eol = QLatin1String("\r\n"); #else eol = QLatin1String("\n"); #endif // Q_OS_WIN32 qint64 absolute_timestamp = DateTime(QDateTime(QDate(2001, 9, 7), QTime(15, 7, 5, 9))).toMilliSeconds(); QHash properties; properties.insert("A", "a"); properties.insert("B", "b"); properties.insert("C", "c"); Log4Qt::PatternFormatter pattern_formatter("%d{ISO8601} [%t] %p %c %x - %m%n:%X"); EXPECT_EQ( pattern_formatter.format(LoggingEvent( test_logger(), Level(Level::DEBUG_INT), "This is the message", "NDC", properties, "main", absolute_timestamp)), "2001-09-07 15:07:05.009 [main] DEBUG Test::TestLog4Qt NDC - This is the message" + eol); pattern_formatter.parseIntegerOption("-1"); pattern_formatter.parseIntegerOption("abc"); qDebug() << pattern_formatter; EXPECT_EQ(mpLoggingEvents->list().count(), 0); resetLogging(); } TEST_F(Log4QtTest, Properties_default) { mDefaultProperties.clear(); mDefaultProperties.setProperty("X", "x"); mProperties.clear(); mProperties.setProperty("A", "a"); mProperties.setProperty("B", ""); mProperties.setProperty("C", QString()); EXPECT_EQ(mProperties.property("A"), "a"); EXPECT_EQ(mProperties.property("B"), ""); EXPECT_EQ(mProperties.property("C"), ""); EXPECT_EQ(mProperties.property("X"), "x"); EXPECT_EQ(mProperties.property("D"), QString()); } TEST_F(Log4QtTest, Properties_names) { mDefaultProperties.clear(); mDefaultProperties.setProperty("X", "x"); mProperties.clear(); mProperties.setProperty("A", "a"); mProperties.setProperty("B", ""); QStringList property_names = mProperties.propertyNames(); EXPECT_EQ(property_names.count(), 3); EXPECT_EQ(property_names.contains("A"), true); EXPECT_EQ(property_names.count("B"), true); EXPECT_EQ(property_names.count("X"), true); } TEST_F(Log4QtTest, Properties_load_device) { mpLoggingEvents->clearList(); QByteArray buffer; QBuffer deviceW(&buffer); QTextStream streamW(&deviceW); buffer.clear(); deviceW.open(QIODevice::WriteOnly); streamW << "Truth = Beauty" << endl; deviceW.close(); QBuffer device(&buffer); QTextStream stream(&device); device.open(QIODevice::ReadOnly); Properties properties; properties.load(&device); EXPECT_EQ(properties.count(), 1); EXPECT_EQ(properties.contains("Truth"), true); EXPECT_EQ(properties.value("Truth"), "Beauty"); EXPECT_EQ(mpLoggingEvents->list().count(), 0); resetLogging(); } TEST_F(Log4QtTest, Properties_load_settings) { QSettings settings(mTemporaryDirectory.path() + "/PropetiesLoadSettings.ini", QSettings::IniFormat); QBitArray bit_array(5, true); settings.setValue("A", "a"); settings.setValue("Group/B", "b"); settings.setValue("Group/C", true); settings.setValue("Group/D", bit_array); settings.setValue("Group/Subgroup/E", "e"); settings.beginGroup("Group"); Properties properties; properties.load(settings); EXPECT_EQ(properties.count(), 3); EXPECT_EQ(properties.contains("B"), true); EXPECT_EQ(properties.value("B"), QString("b")); EXPECT_EQ(properties.contains("C"), true); EXPECT_EQ(properties.value("C"), QString("true")); EXPECT_EQ(properties.contains("D"), true); EXPECT_EQ(properties.value("D"), QString()); } /****************************************************************************** * OptionConverter requires Properties */ TEST_F(Log4QtTest, OptionConverter_boolean) { mpLoggingEvents->clearList(); EXPECT_EQ(OptionConverter::toBoolean("0", true), false); EXPECT_EQ(mpLoggingEvents->list().count(), 0); EXPECT_EQ(OptionConverter::toBoolean("tRuE", false), true); EXPECT_EQ(mpLoggingEvents->list().count(), 0); resetLogging(); } TEST_F(Log4QtTest, OptionConverter_filesize) { mpLoggingEvents->clearList(); bool ok; EXPECT_EQ(OptionConverter::toFileSize("135", &ok), Q_INT64_C(135)); EXPECT_EQ(ok, true); EXPECT_EQ(mpLoggingEvents->list().count(), 0); EXPECT_EQ(OptionConverter::toFileSize("2kb", &ok), Q_INT64_C(2048)); EXPECT_EQ(ok, true); EXPECT_EQ(mpLoggingEvents->list().count(), 0); resetLogging(); } TEST_F(Log4QtTest, OptionConverter_int) { resetLogging(); mpLoggingEvents->clearList(); bool ok; EXPECT_EQ(OptionConverter::toFileSize("12", &ok), 12); EXPECT_EQ(ok, true); EXPECT_EQ(mpLoggingEvents->list().count(), 0); EXPECT_EQ(OptionConverter::toFileSize("12x", &ok), 0); EXPECT_EQ(ok, false); EXPECT_EQ(mpLoggingEvents->list().count(), 1); } TEST_F(Log4QtTest, OptionConverter_level) { resetLogging(); mpLoggingEvents->clearList(); EXPECT_EQ( OptionConverter::toLevel("WaRn", Log4Qt::Level(Log4Qt::Level::ERROR_INT)), Log4Qt::Level(Log4Qt::Level::WARN_INT)); EXPECT_EQ(mpLoggingEvents->list().count(), 0); } TEST_F(Log4QtTest, OptionConverter_substitution) { mpLoggingEvents->clearList(); mProperties.setProperty("D", QString()); EXPECT_EQ(OptionConverter::findAndSubst(mProperties, "D"), ""); EXPECT_EQ(mpLoggingEvents->list().count(), 0); mProperties.setProperty("S1", "begin${A}end"); EXPECT_EQ(OptionConverter::findAndSubst(mProperties, "S1"), "beginaend"); EXPECT_EQ(mpLoggingEvents->list().count(), 0); } TEST_F(Log4QtTest, OptionConverter_target) { mpLoggingEvents->clearList(); bool ok; EXPECT_EQ(OptionConverter::toTarget("STDOUT_TARGET", &ok), (int)ConsoleAppender::STDOUT_TARGET); EXPECT_EQ(ok, true); EXPECT_EQ(mpLoggingEvents->list().count(), 0); EXPECT_EQ(OptionConverter::toTarget("STDERR_TARGET", &ok), (int)ConsoleAppender::STDERR_TARGET); EXPECT_EQ(ok, true); EXPECT_EQ(mpLoggingEvents->list().count(), 0); } /****************************************************************************** * Factory requires OptionConverter */ static Appender *createDiyAppender() { return new NullAppender; } static Filter *createDiyFilter() { return new LevelRangeFilter; } static Layout *createDiyLayout() { return new SimpleLayout; } TEST_F(Log4QtTest, Factory_createAppender) { mpLoggingEvents->clearList(); QObject *p_object = Factory::createAppender("Log4Qt::DebugAppender"); EXPECT_EQ(p_object != 0, true); EXPECT_EQ(QString::fromLatin1(p_object->metaObject()->className()), "Log4Qt::DebugAppender"); DebugAppender *debugAppender = qobject_cast(p_object); if (debugAppender) { debugAppender->setLayout(new SimpleLayout()); debugAppender->requiresLayout(); debugAppender->append(LoggingEvent(test_logger(), Level::WARN_INT, "Message1")); debugAppender->asyncAppend(LoggingEvent(test_logger(), Level::WARN_INT, "Message2")); debugAppender->debug(qDebug() << "test"); } delete p_object; p_object = Factory::createAppender("Log4Qt::NullAppender"); EXPECT_EQ(p_object != 0, true); EXPECT_EQ(QString::fromLatin1(p_object->metaObject()->className()), "Log4Qt::NullAppender"); NullAppender *nullAppender = qobject_cast(p_object); if (nullAppender) { nullAppender->setLayout(new SimpleLayout()); nullAppender->append(LoggingEvent(test_logger(), Level::WARN_INT, "Message1")); nullAppender->asyncAppend(LoggingEvent(test_logger(), Level::WARN_INT, "Message2")); nullAppender->debug(qDebug() << "test"); } delete p_object; p_object = Factory::createAppender("Log4Qt::FileAppender"); EXPECT_EQ(p_object != 0, true); delete p_object; p_object = Factory::createAppender("Log4Qt::ListAppender"); EXPECT_EQ(p_object != 0, true); delete p_object; EXPECT_EQ(mpLoggingEvents->list().count(), 0); Factory::registerAppender("DiyAppender", createDiyAppender); Factory::registerFilter("DiyFilter", createDiyFilter); Factory::registerLayout("DiyLayout", createDiyLayout); Factory::unregisterAppender("DiyAppender"); Factory::unregisterLayout("DiyLayout"); Factory::unregisterFilter("DiyFilter"); qDebug() << "Factory:" << *Factory::instance(); } TEST_F(Log4QtTest, Factory_createFilter) { mpLoggingEvents->clearList(); QObject *p_object = Factory::createFilter("org.apache.log4j.varia.LevelRangeFilter"); EXPECT_EQ(p_object != 0, true); EXPECT_EQ(QString::fromLatin1(p_object->metaObject()->className()), "Log4Qt::LevelRangeFilter"); delete p_object; p_object = Factory::createFilter("org.apache.log4j.varia.DenyAllFilter"); delete p_object; p_object = Factory::createFilter("org.apache.log4j.varia.LevelMatchFilter"); delete p_object; p_object = Factory::createFilter("org.apache.log4j.varia.StringMatchFilter"); delete p_object; EXPECT_EQ(mpLoggingEvents->list().count(), 0); } TEST_F(Log4QtTest, Factory_createLayout) { mpLoggingEvents->clearList(); QObject *p_object = Factory::createLayout("Log4Qt::SimpleLayout"); EXPECT_EQ(p_object != 0, true); EXPECT_EQ(QString::fromLatin1(p_object->metaObject()->className()), "Log4Qt::SimpleLayout"); delete p_object; EXPECT_EQ(mpLoggingEvents->list().count(), 0); } TEST_F(Log4QtTest, Factory_setObjectProperty) { mpLoggingEvents->clearList(); QObject *p_object = Factory::createAppender("Log4Qt::RollingFileAppender"); Factory::setObjectProperty(p_object, "maximumFileSize", "7"); RollingFileAppender *rollingFileAppender = qobject_cast(p_object); if (rollingFileAppender) { rollingFileAppender->setLayout(new SimpleLayout()); rollingFileAppender->append(LoggingEvent(test_logger(), Level::WARN_INT, "Message1")); // rollingFileAppender->asyncAppend(LoggingEvent(test_logger(), Level::WARN_INT, "Message2")); rollingFileAppender->rollOver(); rollingFileAppender->debug(qDebug() << "test"); } EXPECT_EQ(mpLoggingEvents->list().count(), 1); if (mpLoggingEvents->list().count() == 0) { EXPECT_EQ(p_object->property("maximumFileSize").toString(), ""); } delete p_object; } /****************************************************************************** * log4qt/varia */ TEST_F(Log4QtTest, ListAppender) { Log4Qt::ListAppender appender; // Store messages EXPECT_EQ(appender.list().count(), 0); appender.doAppend(LoggingEvent(test_logger(), Level::WARN_INT, "Message1")); appender.doAppend(LoggingEvent(test_logger(), Level::WARN_INT, "Message2")); appender.doAppend(LoggingEvent(test_logger(), Level::WARN_INT, "Message3")); EXPECT_EQ(appender.list().count(), 3); // Delete oldest, if max is set appender.setMaxCount(2); EXPECT_EQ(appender.list().count(), 2); EXPECT_EQ(appender.list().at(0).message(), QString("Message2")); EXPECT_EQ(appender.list().at(1).message(), QString("Message3")); // Ignore new ones added appender.doAppend(LoggingEvent(test_logger(), Level::WARN_INT, "Message4")); EXPECT_EQ(appender.list().count(), 2); EXPECT_EQ(appender.list().at(0).message(), QString("Message2")); EXPECT_EQ(appender.list().at(1).message(), QString("Message3")); // Clear appender.clearList(); EXPECT_EQ(appender.list().count(), 0); } TEST_F(Log4QtTest, DenyAllFilter) { Log4Qt::DenyAllFilter filter; LoggingEvent event(test_logger(), Level::WARN_INT, "Message"); EXPECT_EQ(filter.decide(event), Filter::DENY); } TEST_F(Log4QtTest, LevelMatchFilter) { Log4Qt::LevelMatchFilter filter; filter.setLevelToMatch(Level::fromString("WARN")); filter.setAcceptOnMatch(false); LoggingEvent event(test_logger(), Level::fromString("TRACE"), "Message"); QString decision = enumValueToKey(&filter, "Decision", filter.decide(event)); EXPECT_EQ(decision, "NEUTRAL"); } TEST_F(Log4QtTest, LevelRangeFilter) { QString filter_min_level = "DEBUG"; QString filter_max_level = "ERROR"; Log4Qt::LevelRangeFilter filter; if (!filter_min_level.isEmpty()) filter.setLevelMin(Level::fromString("DEBUG")); if (!filter_max_level.isEmpty()) filter.setLevelMax(Level::fromString("ERROR")); filter.setAcceptOnMatch(false); LoggingEvent event(test_logger(), Level::fromString("TRACE"), "Message"); QString decision = enumValueToKey(&filter, "Decision", filter.decide(event)); EXPECT_EQ(decision, "DENY"); } TEST_F(Log4QtTest, StringMatchFilter) { Log4Qt::StringMatchFilter filter; filter.setStringToMatch("MESSAGE"); filter.setAcceptOnMatch(false); LoggingEvent event(test_logger(), Level::WARN_INT, "This is a message"); QString decision = enumValueToKey(&filter, "Decision", filter.decide(event)); EXPECT_EQ(decision, "NEUTRAL"); } /****************************************************************************** * log4qt */ TEST_F(Log4QtTest, AppenderSkeleton_threshold) { resetLogging(); Log4Qt::ListAppender *p_appender = new Log4Qt::ListAppender(); Log4Qt::Logger *p_logger = test_logger(); p_logger->addAppender(p_appender); // Threshold p_appender->setThreshold(Level::ERROR_INT); p_appender->doAppend(LoggingEvent(p_logger, Level::WARN_INT, "Warn")); p_appender->doAppend(LoggingEvent(p_logger, Level::ERROR_INT, "Error")); p_appender->doAppend(LoggingEvent(p_logger, Level::FATAL_INT, "Fatal")); EXPECT_EQ(p_appender->list().count(), 2); EXPECT_EQ(p_appender->list().at(0).level(), Level(Level::ERROR_INT)); EXPECT_EQ(p_appender->list().at(1).level(), Level(Level::FATAL_INT)); } TEST_F(Log4QtTest, AppenderSkeleton_filter) { resetLogging(); Log4Qt::ListAppender appender; QString filter1_level = "WARN"; QString filter2_level = "WARN"; if (!filter1_level.isEmpty()) { Log4Qt::LevelMatchFilter *p_filter = new Log4Qt::LevelMatchFilter(); p_filter->setLevelToMatch(Level::fromString("WARN")); p_filter->setAcceptOnMatch(false); appender.addFilter(p_filter); } if (!filter2_level.isEmpty()) { Log4Qt::LevelMatchFilter *p_filter = new Log4Qt::LevelMatchFilter(); p_filter->setLevelToMatch(Level::fromString("WARN")); p_filter->setAcceptOnMatch(false); appender.addFilter(p_filter); } appender.doAppend(LoggingEvent(test_logger(), Level::fromString("WARN"), "Message")); EXPECT_EQ(appender.list().count(), 0); } TEST_F(Log4QtTest, BasicConfigurator) { LogManager::resetConfiguration(); resetLogging(); Log4Qt::BasicConfigurator::configure(); Logger *p_logger = LogManager::rootLogger(); EXPECT_EQ(p_logger->appenders().count(), 1); ConsoleAppender *p_appender = qobject_cast(p_logger->appenders().at(0)); EXPECT_EQ(p_appender != 0, true); EXPECT_EQ(p_appender->isActive(), true); EXPECT_EQ(!p_appender->isClosed(), true); EXPECT_EQ(p_appender->target(), QString::fromLatin1("STDOUT_TARGET")); PatternLayout *p_layout = qobject_cast(p_appender->layout()); EXPECT_EQ(p_layout != 0, true); EXPECT_EQ(p_layout->conversionPattern(), QString("%r [%t] %p %c %x - %m%n")); } TEST_F(Log4QtTest, FileAppender) { resetLogging(); QString dir(mTemporaryDirectory.path() + "/FileAppender"); QString file("/log"); Log4Qt::FileAppender appender1(new SimpleLayout(), dir + file, false); appender1.setName("Fileappender1"); appender1.activateOptions(); appender1.doAppend(LoggingEvent(test_logger(), Level::DEBUG_INT, QString("Message 0"))); appender1.doAppend(LoggingEvent(test_logger(), Level::DEBUG_INT, QString("Message 1"))); appender1.close(); QStringList expected; QString result; expected << "log"; if (!validateDirContents(dir, expected, result)) FAIL(); expected.clear(); expected << "DEBUG - Message 0" << "DEBUG - Message 1"; if (!validateFileContents(dir + file, expected, result)) FAIL(); Log4Qt::FileAppender appender2(new SimpleLayout(), dir + file, false); appender2.setName("Fileappender2"); appender2.activateOptions(); appender2.doAppend(LoggingEvent(test_logger(), Level::DEBUG_INT, QString("Message 2"))); appender2.doAppend(LoggingEvent(test_logger(), Level::DEBUG_INT, QString("Message 3"))); appender2.close(); expected.clear(); expected << "log"; if (!validateDirContents(dir, expected, result)) FAIL(); expected.clear(); expected << "DEBUG - Message 2" << "DEBUG - Message 3"; if (!validateFileContents(dir + file, expected, result)) FAIL(); Log4Qt::FileAppender appender3(new SimpleLayout(), dir + file, true); appender3.setName("Fileappender3"); appender3.activateOptions(); appender3.doAppend(LoggingEvent(test_logger(), Level::DEBUG_INT, QString("Message 4"))); appender3.doAppend(LoggingEvent(test_logger(), Level::DEBUG_INT, QString("Message 5"))); appender3.close(); expected.clear(); expected << "log"; if (!validateDirContents(dir, expected, result)) FAIL(); expected.clear(); expected << "DEBUG - Message 2" << "DEBUG - Message 3" << "DEBUG - Message 4" << "DEBUG - Message 5"; if (!validateFileContents(dir + file, expected, result)) FAIL(); EXPECT_EQ(mpLoggingEvents->list().count(), 0); Log4Qt::FileAppender appender4(new SimpleLayout(), ""); appender4.activateOptions(); Log4Qt::FileAppender appender5(new SimpleLayout(), dir + file, false, false); appender5.debug(qDebug() << "test"); QFile fileAbc("/abc"); appender5.removeFile(fileAbc); appender5.renameFile(fileAbc, "/bcd"); } TEST_F(Log4QtTest, DailyRollingFileAppender) { resetLogging(); qDebug() << "The test is time based and takes approximately 3 minutes ..."; QString dir(mTemporaryDirectory.path() + "/DailyRollingFileAppender"); QString file("/log"); // Using a RollingFileAppender with 2 files history and 3 messages per file Log4Qt::DailyRollingFileAppender appender; appender.setName("DailyRollingFileAppender"); appender.setFile(dir + file); appender.setLayout(new SimpleLayout()); appender.setDatePattern(DailyRollingFileAppender::MINUTELY_ROLLOVER); // Start on a full minute QDateTime now = QDateTime::currentDateTime(); // QThread::sleep((60 - now.time().second()) * 1000); appender.activateOptions(); Log4Qt::DailyRollingFileAppender appender1; appender1.setName("DailyRollingFileAppender1"); appender1.setFile(dir + file + "1"); appender1.setLayout(new SimpleLayout()); appender1.setDatePattern(DailyRollingFileAppender::HOURLY_ROLLOVER); appender1.activateOptions(); Log4Qt::DailyRollingFileAppender appender2; appender2.setName("DailyRollingFileAppender2"); appender2.setFile(dir + file + "2"); appender2.setLayout(new SimpleLayout()); appender2.setDatePattern(DailyRollingFileAppender::HALFDAILY_ROLLOVER); appender2.activateOptions(); Log4Qt::DailyRollingFileAppender appender3; appender3.setName("DailyRollingFileAppender3"); appender3.setFile(dir + file + "3"); appender3.setLayout(new SimpleLayout()); appender3.setDatePattern(DailyRollingFileAppender::WEEKLY_ROLLOVER); // appender3.activateOptions(); Log4Qt::DailyRollingFileAppender appender4; appender4.setName("DailyRollingFileAppender4"); appender4.setFile(dir + file + "4"); appender4.setLayout(new SimpleLayout()); appender4.setDatePattern(DailyRollingFileAppender::MONTHLY_ROLLOVER); appender4.activateOptions(); qDebug() << " 1 / 7"; appender.doAppend(LoggingEvent(test_logger(), Level::DEBUG_INT, QString("Message 0"))); int i; for (i = 1; i < 1; i++) { QThread::sleep(1 * 1000); qDebug() << " " << i + 1 << "/" << 7; appender.doAppend(LoggingEvent(test_logger(), Level::DEBUG_INT, QString("Message %1").arg(i))); } appender.asyncAppend(LoggingEvent(test_logger(), Level::DEBUG_INT, QString("Message async"))); appender.debug(qDebug() << "test"); appender.rollOver(); EXPECT_EQ(mpLoggingEvents->list().count(), 0); // Validate directory QStringList expected; QString result; expected << "log" << "log" + dailyRollingFileAppenderSuffix(now.addSecs(60)) << "log" + dailyRollingFileAppenderSuffix(now.addSecs(120)); if (!validateDirContents(dir, expected, result)) FAIL(); // Validate files expected.clear(); expected << "DEBUG - Message 6"; if (!validateFileContents(dir + file, expected, result)) FAIL(); expected.clear(); expected << "DEBUG - Message 0" << "DEBUG - Message 1" << "DEBUG - Message 2"; if (!validateFileContents(dir + file + dailyRollingFileAppenderSuffix(now.addSecs(60)), expected, result)) FAIL(); expected.clear(); expected << "DEBUG - Message 3" << "DEBUG - Message 4" << "DEBUG - Message 5"; if (!validateFileContents(dir + file + dailyRollingFileAppenderSuffix(now.addSecs(120)), expected, result)) FAIL(); } TEST_F(Log4QtTest, LoggingEvent_stream) { resetLogging(); qint64 timestamp = DateTime(QDateTime(QDate(2001, 9, 7), QTime(15, 7, 5, 9))).toMilliSeconds(); QHash properties; properties.insert("A", "a"); properties.insert("B", "b"); properties.insert("C", "c"); LoggingEvent original(0, Level(Level::WARN_INT), "This is a message", "NDC", properties, "main", timestamp); QByteArray array; QBuffer buffer(&array); buffer.open(QIODevice::WriteOnly); QDataStream stream(&buffer); stream << original; buffer.close(); buffer.open(QIODevice::ReadOnly); LoggingEvent streamed; stream >> streamed; buffer.close(); EXPECT_EQ(original.level(), streamed.level()); EXPECT_EQ(original.loggerName(), streamed.loggerName()); EXPECT_EQ(original.message(), streamed.message()); EXPECT_EQ(original.ndc(), streamed.ndc()); EXPECT_EQ(original.properties().count(), streamed.properties().count()); QStringList keys = original.properties().keys(); QString key; Q_FOREACH (key, keys) { EXPECT_EQ(streamed.properties().contains(key), true); EXPECT_EQ(original.properties().value(key), streamed.properties().value(key)); } EXPECT_EQ(original.sequenceNumber(), streamed.sequenceNumber()); EXPECT_EQ(original.threadName(), streamed.threadName()); EXPECT_EQ(original.timeStamp(), streamed.timeStamp()); EXPECT_EQ(mpLoggingEvents->list().count(), 0); } TEST_F(Log4QtTest, LogManager_configureLogLogger) { resetLogging(); LogManager::logLogger()->removeAppender(mpLoggingEvents); LogManager::resetConfiguration(); Log4Qt::Logger *p_logger = LogManager::logLogger(); EXPECT_EQ(p_logger->appenders().count(), 2); ConsoleAppender *p_appender; TTCCLayout *p_layout; p_appender = qobject_cast(p_logger->appenders().at(0)); EXPECT_EQ(p_appender != 0, true); EXPECT_EQ(p_appender->isActive(), true); EXPECT_EQ(!p_appender->isClosed(), true); EXPECT_EQ(p_appender->target(), QString::fromLatin1("STDOUT_TARGET")); p_layout = qobject_cast(p_appender->layout()); EXPECT_EQ(p_layout != 0, true); p_appender = qobject_cast(p_logger->appenders().at(1)); EXPECT_EQ(p_appender != 0, true); EXPECT_EQ(p_appender->isActive(), true); EXPECT_EQ(!p_appender->isClosed(), true); EXPECT_EQ(p_appender->target(), QString::fromLatin1("STDERR_TARGET")); p_layout = qobject_cast(p_appender->layout()); EXPECT_EQ(p_layout != 0, true); TTCCLayout testLayout("yyyy-MM-dd hh:mm:ss.zzz"); testLayout.setDateFormat(TTCCLayout::NONE); testLayout.setDateFormat(TTCCLayout::TIME_ABSOLUTE); testLayout.setDateFormat(TTCCLayout::DATE); testLayout.setDateFormat(TTCCLayout::TIME_RELATIVE); TTCCLayout testLayout1(TTCCLayout::ISO8601); testLayout1.debug(qDebug() << "test"); } TEST_F(Log4QtTest, PropertyConfigurator_missing_appender) { LogManager::resetConfiguration(); resetLogging(); mDefaultProperties.clear(); mProperties.clear(); mProperties.setProperty("log4j.logger.MissingAppender", "INHERITED, A"); EXPECT_EQ(!PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 1); EXPECT_EQ(mpLoggingEvents->list().count(), 1); } TEST_F(Log4QtTest, PropertyConfigurator_unknown_appender_class) { LogManager::resetConfiguration(); resetLogging(); mDefaultProperties.clear(); mProperties.clear(); mProperties.setProperty("log4j.logger.UnknownAppender", "INHERITED, A"); mProperties.setProperty("log4j.appender.A", "org.apache.log4j.UnknownAppender"); EXPECT_EQ(!PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 1); EXPECT_EQ(mpLoggingEvents->list().count(), 2); // Warning from Factory, Error PropertyConfigurator } TEST_F(Log4QtTest, PropertyConfigurator_missing_layout) { resetLogging(); mDefaultProperties.clear(); mProperties.clear(); mProperties.setProperty("log4j.logger.MissingLayout", "INHERITED, A"); mProperties.setProperty("log4j.appender.A", "org.apache.log4j.ConsoleAppender"); EXPECT_EQ(!PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 1); EXPECT_EQ(mpLoggingEvents->list().count(), 1); } TEST_F(Log4QtTest, PropertyConfigurator_unknown_layout_class) { resetLogging(); mDefaultProperties.clear(); mProperties.clear(); mProperties.setProperty("log4j.logger.UnknownLayout", "INHERITED, A"); mProperties.setProperty("log4j.appender.A", "org.apache.log4j.ConsoleAppender"); mProperties.setProperty("log4j.appender.A.layout", "org.apache.log4j.UnknownLayout"); EXPECT_EQ(!PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 1); EXPECT_EQ(mpLoggingEvents->list().count(), 2); // Warning from Factory, Error PropertyConfigurator } TEST_F(Log4QtTest, PropertyConfigurator_reset) { resetLogging(); mDefaultProperties.clear(); mProperties.clear(); // - Create a logger with an appender // - If the reset flag is not set, configure must leave the appender // - If the reset flag is set to an invalid value, configure must raise an // error and leave the appender // - If the reset flag is set, configure must remove the appender const QLatin1String key_reset("log4j.reset"); test_logger()->addAppender(new Log4Qt::ListAppender); mProperties.setProperty(key_reset, "false"); EXPECT_EQ(PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 0); EXPECT_EQ(mpLoggingEvents->list().count(), 0); EXPECT_EQ(test_logger()->appenders().count(), 1); mProperties.setProperty(key_reset, "No boolean"); EXPECT_EQ(!PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 1); EXPECT_EQ(mpLoggingEvents->list().count(), 1); EXPECT_EQ(test_logger()->appenders().count(), 1); resetLogging(); mProperties.setProperty(key_reset, "true"); EXPECT_EQ(PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 0); EXPECT_EQ(mpLoggingEvents->list().count(), 0); EXPECT_EQ(test_logger()->appenders().count(), 0); } TEST_F(Log4QtTest, PropertyConfigurator_debug) { resetLogging(); mDefaultProperties.clear(); mProperties.clear(); // - Set the log logger level to INFO // - If debug is not set, configure must leave the log logger level // unaltered // - If debug is set, but with no valid level string, configure must set // the log logger level to DEBUG // - If debug is set to the level TRACE, configure must set the log logger // level to TRACE const QLatin1String key_debug("log4j.Debug"); Logger *p_logger = LogManager::logLogger(); p_logger->setLevel(Level::INFO_INT); EXPECT_EQ(PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 0); EXPECT_EQ(mpLoggingEvents->list().count(), 0); EXPECT_EQ(p_logger->level(), Level(Level::INFO_INT)); mProperties.setProperty(key_debug, "true"); EXPECT_EQ(PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 0); // EXPECT_EQ(mpLoggingEvents->list().count(), 1); // Warning from Level::fromString() & several debug messages EXPECT_EQ(p_logger->level(), Level(Level::DEBUG_INT)); mpLoggingEvents->clearList(); mProperties.setProperty(key_debug, "TRACE"); EXPECT_EQ(PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 0); // EXPECT_EQ(mpLoggingEvents->list().count(), 1); // Warning from PropertyConfigurator & several debug/trace // messages EXPECT_EQ(p_logger->level(), Level(Level::TRACE_INT)); } TEST_F(Log4QtTest, PropertyConfigurator_threshold) { resetLogging(); mDefaultProperties.clear(); mProperties.clear(); // - Set the repository threshold to INFO // - If the threshold is not set, configure must leave the repository // threshold unaltered // - If the threshold is set to an invalid value, configure must raise an // error and set the threshold to ALL // - If the threshold is set to WARN, configure must set the repository // threshold to WARN const QLatin1String key_threshold("log4j.threshold"); LogManager::loggerRepository()->setThreshold(Level::INFO_INT); EXPECT_EQ(PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 0); EXPECT_EQ(mpLoggingEvents->list().count(), 0); EXPECT_EQ(LogManager::loggerRepository()->threshold(), Level(Level::INFO_INT)); mProperties.setProperty(key_threshold, "Not a value"); EXPECT_EQ(!PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 1); EXPECT_EQ(mpLoggingEvents->list().count(), 2); // Warning by Level, Error from OptionConverter EXPECT_EQ(LogManager::loggerRepository()->threshold(), Level(Level::ALL_INT)); mpLoggingEvents->clearList(); mProperties.setProperty(key_threshold, "WARN"); EXPECT_EQ(PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 0); EXPECT_EQ(mpLoggingEvents->list().count(), 0); EXPECT_EQ(LogManager::loggerRepository()->threshold(), Level(Level::WARN_INT)); } TEST_F(Log4QtTest, PropertyConfigurator_handleQtMessages) { resetLogging(); mDefaultProperties.clear(); mProperties.clear(); // - Set handle Qt messages to true // - If handle Qt messages is not set, configure must leave handle Qt // messages unaltered // - If handle Qt messages is set to an invalid value, configure must raise // an error and set handle Qt messages to false // - If handle Qt messages is true, configure must set handle Qt messages // to true const QLatin1String key_handle_qt_messages("log4j.handleQtMessages"); LogManager::setHandleQtMessages(true); EXPECT_EQ(PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 0); EXPECT_EQ(mpLoggingEvents->list().count(), 0); EXPECT_EQ(LogManager::handleQtMessages(), true); mProperties.setProperty(key_handle_qt_messages, "No boolean"); EXPECT_EQ(!PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 1); EXPECT_EQ(mpLoggingEvents->list().count(), 1); EXPECT_EQ(LogManager::handleQtMessages(), false); mpLoggingEvents->clearList(); mProperties.setProperty(key_handle_qt_messages, "true"); EXPECT_EQ(PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 0); EXPECT_EQ(mpLoggingEvents->list().count(), 0); EXPECT_EQ(LogManager::handleQtMessages(), true); } TEST_F(Log4QtTest, PropertyConfigurator_example) { LogManager::resetConfiguration(); resetLogging(); mDefaultProperties.clear(); mProperties.clear(); QString file(mTemporaryDirectory.path() + "/RollingFileAppender/log"); // Based on the JavaDoc example: // - A1: JavaDoc uses SyslogAppender, which is not available on all platforms // - A2: JavaDoc does not set a file, which causes error on activation // - A2: JavaDoc uses default values for file size and backup index. Use // different values. // - A2 Layout: ContextPrinting uses default enabled. Use disabled instead. // - root: JavaDoc uses default level DEBUG. Use INFO instead. // - SECURITY: JavaDoc uses INHERIT. Use INHERITED instead // - log4j.logger.class.of.the.day: JavaDoc uses INHERIT. Use INHERITED // instead // Appender A1: ConsoleAppender with PatternLayout mProperties.setProperty("log4j.appender.A1", "org.apache.log4j.ConsoleAppender"); mProperties.setProperty("log4j.appender.A1.Target", "System.Out"); mProperties.setProperty("log4j.appender.A1.layout", "org.apache.log4j.PatternLayout"); mProperties.setProperty("log4j.appender.A1.layout.ConversionPattern", "%-4r %-5p %c{2} %M.%L %x - %m\n"); // Appender A2: RollingFileAppender with TTCCLayout mProperties.setProperty("log4j.appender.A2", "org.apache.log4j.RollingFileAppender"); mProperties.setProperty("log4j.appender.A2.File", file); mProperties.setProperty("log4j.appender.A2.MaxFileSize", "13MB"); mProperties.setProperty("log4j.appender.A2.MaxBackupIndex", "7"); mProperties.setProperty("log4j.appender.A2.layout", "org.apache.log4j.TTCCLayout"); mProperties.setProperty("log4j.appender.A2.layout.ContextPrinting", "disabled"); mProperties.setProperty("log4j.appender.A2.layout.DateFormat", "ISO8601"); // Root Logger: Uses A2 mProperties.setProperty("log4j.rootLogger", "INFO, A2"); // Logger SECURITY: Uses A1 mProperties.setProperty("log4j.logger.SECURITY", "INHERITED, A1"); mProperties.setProperty("log4j.additivity.SECURITY", "false"); // Logger SECURITY.access: mProperties.setProperty("log4j.logger.SECURITY.access", "WARN"); // Logger class.of.the.day: mProperties.setProperty("log4j.logger.class.of.the.day", "INHERITED"); // No warnings, no errors expected EXPECT_EQ(PropertyConfigurator::configure(mProperties), true); EXPECT_EQ(ConfiguratorHelper::configureError().count(), 0); EXPECT_EQ(mpLoggingEvents->list().count(), 0); // Root logger Logger *p_logger; p_logger = LogManager::rootLogger(); EXPECT_EQ(p_logger->level(), Level(Level::INFO_INT)); EXPECT_EQ(p_logger->appenders().count(), 1); Log4Qt::RollingFileAppender *p_a2 = qobject_cast(p_logger->appenders().at(0)); EXPECT_EQ(p_a2 != 0, true); EXPECT_EQ(p_a2->file(), file); EXPECT_EQ(p_a2->maximumFileSize(), Q_INT64_C(13 * 1024 * 1024)); EXPECT_EQ(p_a2->maxBackupIndex(), 7); Log4Qt::TTCCLayout *p_a2layout = qobject_cast(p_a2->layout()); EXPECT_EQ(p_a2layout != 0, true); EXPECT_EQ(p_a2layout->contextPrinting(), false); EXPECT_EQ(p_a2layout->dateFormat(), QString::fromLatin1("ISO8601")); // Logger SECURITY EXPECT_EQ(LogManager::exists("SECURITY"), true); p_logger = LogManager::logger("SECURITY"); EXPECT_EQ(p_logger->level(), Level(Level::NULL_INT)); EXPECT_EQ(p_logger->appenders().count(), 1); Log4Qt::ConsoleAppender *p_a1 = qobject_cast(p_logger->appenders().at(0)); EXPECT_EQ(p_a1 != 0, true); EXPECT_EQ(p_a1->target(), QString::fromLatin1("STDOUT_TARGET")); Log4Qt::PatternLayout *p_a1layout = qobject_cast(p_a1->layout()); EXPECT_EQ(p_a1layout != 0, true); EXPECT_EQ(p_a1layout->conversionPattern(), QString::fromLatin1("%-4r %-5p %c{2} %M.%L %x - %m\n")); // Logger SECURITY::access EXPECT_EQ(LogManager::exists("SECURITY::access"), true); p_logger = LogManager::logger("SECURITY::access"); EXPECT_EQ(p_logger->level(), Level(Level::WARN_INT)); // Logger class::of::the::day EXPECT_EQ(LogManager::exists("class::of::the::day"), true); } TEST_F(Log4QtTest, RollingFileAppender) { resetLogging(); QString dir(mTemporaryDirectory.path() + "/RollingFileAppender"); QString file("/log"); // Using a RollingFileAppender with 2 files history and 3 messages per file Log4Qt::RollingFileAppender appender; appender.setName("RollingFileAppender"); appender.setFile(dir + file); appender.setLayout(new SimpleLayout()); appender.setMaxBackupIndex(2); appender.setMaximumFileSize(40); appender.activateOptions(); // Output 9 messages int i; for (i = 0; i < 10; i++) appender.doAppend(LoggingEvent(test_logger(), Level::DEBUG_INT, QString("Message %1").arg(i))); // No warnings or errors expected EXPECT_EQ(mpLoggingEvents->list().count(), 0); // Validate diretcory QStringList expected; QString result; expected << "log" << "log.1" << "log.2"; if (!validateDirContents(dir, expected, result)) FAIL(); // Validate files expected.clear(); expected << "DEBUG - Message 9"; if (!validateFileContents(dir + file, expected, result)) FAIL(); expected.clear(); expected << "DEBUG - Message 6" << "DEBUG - Message 7" << "DEBUG - Message 8"; if (!validateFileContents(dir + file + ".1", expected, result)) FAIL(); expected.clear(); expected << "DEBUG - Message 3" << "DEBUG - Message 4" << "DEBUG - Message 5"; if (!validateFileContents(dir + file + ".2", expected, result)) FAIL(); EXPECT_EQ(mpLoggingEvents->list().count(), 0); } TEST_F(Log4QtTest, LogError) { Log4Qt::LogError logErrorNull; Log4Qt::LogError logError("abc", 0, "Test", "123456", LogError::LATIN1); logError.translatedMessage(); qDebug() << logError.lastError() << logError; logError.setLastError(logErrorNull); QDataStream stream; stream << logError; stream >> logError; } ukui-interface/tests/unit_test_log4qt/unit_test_log4qt.pro0000664000175000017500000000167715167726076023153 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2019-08-22T11:12:59 # #------------------------------------------------- QT += core QT -= gui TEMPLATE = app TARGET = unit_test_log4qt target.source += $$TARGET target.path = ./ #代码覆盖率工具gcov QMAKE_LFLAGS +=-fprofile-arcs -ftest-coverage QMAKE_CXXFLAGS += --coverage -fno-inline -fno-access-control -fno-exceptions LIBS += -lgtest_main -lpthread LIBS += -L$$[QT_INSTALL_LIBS] -lgtest -lgcov #OBJECTS_DIR = ./obj #MOC_DIR = ./moc CONFIG += link_pkgconfig PKGCONFIG += #log4qt include($$PWD/../../src/log4qt/ukui-log4qt.pri) #打桩工具 TEST_UTILS_PATH = $$PWD/../kt-test-utils # Include directories INCLUDEPATH += $$PROJECT_ROOTDIR \ $$TEST_UTILS_PATH/cpp-stub \ $$TEST_UTILS_PATH/cpp-stub-ext \ $$PWD/../../src/log4qt SOURCES += unit_test_log4qt.cpp \ main.cpp HEADERS += ukui-interface/tests/tests.pro0000664000175000017500000000070315167726076015462 0ustar fengfengTEMPLATE = subdirs SUBDIRS = unit_test_common \ unit_test_log4qt # 打桩工具 # Define paths TEST_UTILS_PATH = $$PWD/kt-test-utils # Header files (if needed) HEADERS += $$files($$TEST_UTILS_PATH/cpp-stub/*.h $$TEST_UTILS_PATH/cpp-stub/*.hpp) \ $$files($$TEST_UTILS_PATH/cpp-stub-ext/*.h) # Gather source files SOURCES += $$files($$TEST_UTILS_PATH/cpp-stub/*.cpp) \ $$files($$TEST_UTILS_PATH/cpp-stub-ext/*.cpp) ukui-interface/tests/unit_test_common/0000775000175000017500000000000015167726076017164 5ustar fengfengukui-interface/tests/unit_test_common/main.cpp0000664000175000017500000000146315167726076020620 0ustar fengfeng/* * Copyright (C) 2025 KylinSoft Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include int main(int argc, char **argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ukui-interface/tests/unit_test_common/unit_test_common.pro0000664000175000017500000000221615167726076023275 0ustar fengfeng#------------------------------------------------- # # Project created by QtCreator 2019-08-22T11:12:59 # #------------------------------------------------- QT += core QT -= gui TEMPLATE = app TARGET = unit_test_common target.source += $$TARGET target.path = ./ #代码覆盖率工具gcov QMAKE_LFLAGS +=-fprofile-arcs -ftest-coverage QMAKE_CXXFLAGS += --coverage -fno-inline -fno-access-control -fno-exceptions LIBS += -lgtest_main -lpthread -liniparser LIBS += -L$$[QT_INSTALL_LIBS] -lgtest -lgcov #OBJECTS_DIR = ./obj #MOC_DIR = ./moc CONFIG += link_pkgconfig PKGCONFIG += #打桩工具 TEST_UTILS_PATH = $$PWD/../kt-test-utils # Include directories INCLUDEPATH += $$PROJECT_ROOTDIR \ $$TEST_UTILS_PATH/cpp-stub \ $$TEST_UTILS_PATH/cpp-stub-ext \ $$PWD/../../src/common SOURCES += unit_test_common.cpp \ ../../src/common/kylin-com4cxx.cpp \ ../../src/common/kylin-com4c.c \ ../../src/common/kylin-ini.c \ main.cpp HEADERS += ../../src/common/kylin-ini.h \ ../../src/common/kylin-com4c.h \ ../../src/common/kylin-com4cxx.h ukui-interface/tests/unit_test_common/unit_test_common.cpp0000664000175000017500000001624215167726076023263 0ustar fengfeng/* * Copyright (C) 2025 KylinSoft Co., Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see . * **/ #include #include #include "kylin-com4cxx.h" #include "kylin-ini.h" #include "kylin-com4c.h" #include class CommonCxxInterfaceTest : public testing::Test { protected: static void SetUpTestSuite() {} static void TearDownTestSuite() {} }; TEST_F(CommonCxxInterfaceTest, getLsbRelease) { QString strvalue = QString(KDKGetLSBRelease("DISTRIB_ID").c_str()); EXPECT_EQ(strvalue, "Kylin"); } TEST_F(CommonCxxInterfaceTest, getOsRelease) { QString strvalue = QString(KDKGetOSRelease("NAME").c_str()); EXPECT_EQ(strvalue, "Kylin"); } TEST_F(CommonCxxInterfaceTest, getKyInfo) { QString strvalue = QString(KDKGetKYInfo("dist", "name").c_str()); EXPECT_EQ(strvalue, ""); } TEST_F(CommonCxxInterfaceTest, getPrjCodeName) { QString strvalue = QString(KDKGetPrjCodeName().c_str()); EXPECT_EQ(strvalue.contains("V1"), true); } TEST_F(CommonCxxInterfaceTest, getCpuModelName) { QString strvalue = QString(KDKGetCpuModelName().c_str()); EXPECT_EQ(strvalue.isEmpty(), false); } TEST_F(CommonCxxInterfaceTest, getSpecHDPlatform) { QString strvalue = QString(KDKGetSpecHDPlatform().c_str()); EXPECT_EQ(strvalue, "default"); } TEST_F(CommonCxxInterfaceTest, getVirtEnv) { QString strvalue = QString(KDKGetVirtEnv().c_str()); EXPECT_EQ(strvalue.contains("none"), true); } // 辅助函数,用于比较两个字符串是否相等(忽略结尾的空字符) bool StringsAreEqual(const char *str1, const char *str2) { if (str1 == nullptr && str2 == nullptr) return true; if (str1 == nullptr || str2 == nullptr) return false; return strcmp(str1, str2) == 0; } // 测试strstripr函数 TEST(StrStripTest, StrStriprTest_NoSpaces) { char str[] = "hello"; char *result = strstripr(str, 0); EXPECT_TRUE(StringsAreEqual(result, "hello")); } TEST(StrStripTest, StrStriprTest_TrailingSpaces) { char str[] = "hello "; char *result = strstripr(str, 0); EXPECT_TRUE(StringsAreEqual(result, "hello")); } TEST(StrStripTest, StrStriprTest_TrailingNewline) { char str[] = "hello\n"; char *result = strstripr(str, 0); EXPECT_TRUE(StringsAreEqual(result, "hello")); } TEST(StrStripTest, StrStriprTest_TrailingQuote) { char str[] = "hello\""; char *result = strstripr(str, 1); EXPECT_TRUE(StringsAreEqual(result, "hello")); } TEST(StrStripTest, StrStriprTest_TrailingQuoteAndSpaces) { char str[] = "hello \" "; char *result = strstripr(str, 1); EXPECT_TRUE(StringsAreEqual(result, "hello ")); result = strstripr(result, 0); // 再次去除尾部空格 EXPECT_TRUE(StringsAreEqual(result, "hello")); } // 测试strstripl函数 TEST(StrStripTest, StrStriplTest_NoSpaces) { char str[] = "hello"; char *result = strstripl(str, 0); EXPECT_TRUE(StringsAreEqual(result, "hello")); } TEST(StrStripTest, StrStriplTest_LeadingSpaces) { char str[] = " hello"; char *result = strstripl(str, 0); EXPECT_TRUE(StringsAreEqual(result, "hello")); } TEST(StrStripTest, StrStriplTest_LeadingNewline) { char str[] = "\nhello"; char *result = strstripl(str, 0); EXPECT_TRUE(StringsAreEqual(result, "hello")); } TEST(StrStripTest, StrStriplTest_LeadingQuote) { char str[] = "\"hello"; char *result = strstripl(str, 1); EXPECT_TRUE(StringsAreEqual(result, "hello")); } TEST(StrStripTest, StrStriplTest_LeadingQuoteAndSpaces) { char str[] = " \" hello"; char *result = strstripl(str, 1); EXPECT_TRUE(StringsAreEqual(result, " hello")); result = strstripl(result, 0); // 再次去除首部空格 EXPECT_TRUE(StringsAreEqual(result, "hello")); } // 测试strstrip函数 TEST(StrStripTest, StrStripTest_NoSpaces) { char str[] = "hello"; char *result = strstrip(str, 0); EXPECT_TRUE(StringsAreEqual(result, "hello")); } TEST(StrStripTest, StrStripTest_LeadingAndTrailingSpaces) { char str[] = " hello "; char *result = strstrip(str, 0); EXPECT_TRUE(StringsAreEqual(result, "hello")); } TEST(StrStripTest, StrStripTest_LeadingNewlineTrailingSpaces) { char str[] = "\nhello "; char *result = strstrip(str, 0); EXPECT_TRUE(StringsAreEqual(result, "hello")); } TEST(StrStripTest, StrStripTest_LeadingAndTrailingQuote) { char str[] = "\"hello\""; char *result = strstrip(str, 1); EXPECT_TRUE(StringsAreEqual(result, "hello")); } TEST(StrStripTest, StrStripTest_Complex) { char str[] = " \" hello \" \t\n"; char *result = strstrip(str, 1); EXPECT_TRUE(StringsAreEqual(result, "hello")); } class KylinCom4cTest : public ::testing::Test { protected: static void SetUpTestSuite() {} static void TearDownTestSuite() {} }; TEST_F(KylinCom4cTest, GetLsbRelease) { const char *key = "DISTRIB_ID"; char value[256]; int result = kdk_get_lsbrelease(key, value, sizeof(value)); EXPECT_GT(result, 0) << "kdk_get_lsbrelease() failed to get value"; EXPECT_NE(std::string(value).find("Ubuntu"), std::string::npos) << "Unexpected LSB release value: " << value; // 以Ubuntu为例,根据实际情况修改 } TEST_F(KylinCom4cTest, GetOsRelease) { const char *key = "PRETTY_NAME"; char value[256]; int result = kdk_get_osrelease(key, value, sizeof(value)); EXPECT_GT(result, 0) << "kdk_get_osrelease() failed to get value"; EXPECT_NE(std::string(value).find("Ubuntu"), std::string::npos) << "Unexpected OS release value: " << value; // 以Ubuntu为例,根据实际情况修改 } TEST_F(KylinCom4cTest, GetPrjCodename) { char value[256]; int result = kdk_get_prjcodename(value, sizeof(value)); EXPECT_GT(result, 0) << "kdk_get_prjcodename() failed to get value"; // 根据实际情况验证PROJECT_CODENAME的值 } TEST_F(KylinCom4cTest, GetCpuModelName) { char modelName[128]; int result = kdk_get_cpumodelname(modelName, sizeof(modelName)); EXPECT_GT(result, 0) << "kdk_get_cpumodelname() failed to get value"; // 根据实际情况验证CPU型号的值 } TEST_F(KylinCom4cTest, GetSpechdPlatform) { char platformName[128]; int result = kdk_get_spechdplatform(platformName, sizeof(platformName)); EXPECT_GT(result, 0) << "kdk_get_spechdplatform() failed to get value"; // 根据实际情况验证特定硬件平台信息的值,可能默认为"default" } TEST_F(KylinCom4cTest, GetVirtEnv) { char virtenv[128]; int result = kdk_get_virtenv(virtenv, sizeof(virtenv)); EXPECT_GT(result, 0) << "kdk_get_virtenv() failed to get value"; // 根据实际情况验证虚拟化环境标志的值,可能为"none"、"kvm"等 } ukui-interface/tests/auto_test.sh0000775000175000017500000000303515167726076016145 0ustar fengfeng#!/bin/bash # 设置退出脚本当命令失败时 (非零退出状态) #set -e # 函数:运行单元测试 run_unit_tests() { local pattern="unit_test_*" # 遍历所有匹配模式的目录 for dir in $pattern; do if [ -d "$dir" ] && [ -x "$dir/$(basename "$dir")" ]; then echo "Running tests in $dir..." # 执行单元测试 (cd "$dir" && "./$(basename "$dir")") # 收集代码覆盖率数据 echo "Collecting coverage data..." (cd "$dir" && (find ./ -name '*.o' | xargs gcov --preserve-paths)) else echo "Skipping non-existent or non-executable directory: $dir, $dir/$(basename "$dir")" fi done } # 上传 result.zip 到平台 URL=$1 upload_result() { echo "current pwd : $(pwd)" # 收集覆盖率信息 lcov -d . -c -o r.info # 删除不需要的文件或路径 lcov -r r.info "$(pwd)/unit_test_*" "$(pwd)/../registeredSession/universalinterface.cpp" "/usr/include/*" "/opt/*" -o coverage.info # 生成html覆盖率报告 genhtml "$(pwd)/coverage.info" -o result # 打包 zip -r result.zip result # 上传平台 curl --insecure -X POST -F "file=@/$(pwd)/result.zip" -F "package=ukui-control-center" -F "username=hesisheng" $URL echo "all parameter : $@" } # 编译项目 echo "Compiling the project..." qmake . && make # 运行各个单元测试 echo "Running unit tests..." run_unit_tests # 上传到平台 #upload_result echo "All tests have been run successfully, and coverage data has been collected." ukui-interface/NEWS0000664000175000017500000000000015167726064013116 0ustar fengfeng