Browse Source

Z991239-635 #comment feature: 添加厂商日志库,暂时 Windows 下编译成功

gifur 5 years ago
parent
commit
ee9309fd00

+ 5 - 0
DevAdapter/CMakeLists.txt

@@ -83,12 +83,17 @@ endif(RVC_INTEGRATE_BUILD)
 
 endmacro(rvc_aggereate_runtime_file)
 
+
 set(DEVADAPTER_INCLUDES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
 include_directories(${DEVADAPTER_INCLUDES_DIR})
 
 # 用于收录每一个厂商目录下 bin/*.dll 和 lib/*.so 文件
 set(RVC_VENDOR_DEP_LIB_DIRS "")
 
+if(RVC_INTEGRATE_BUILD)
+    add_subdirectory(self)
+endif(RVC_INTEGRATE_BUILD)
+
 add_subdirectory(cmbsz)
 
 if(RVC_INTEGRATE_BUILD)

+ 1 - 0
DevAdapter/self/CMakeLists.txt

@@ -0,0 +1 @@
+add_subdirectory(liblog4vendor)

+ 266 - 0
DevAdapter/self/liblog4vendor/.gitignore

@@ -0,0 +1,266 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush
+.cr/
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+

+ 28 - 0
DevAdapter/self/liblog4vendor/CMakeLists.txt

@@ -0,0 +1,28 @@
+rvc_dev_define_module("log4vendor")
+
+set(RAW_VERSION_STRING "1.0.0")
+
+set(${MODULE_PREFIX}_SRCS
+    liblog4vendor.cpp
+    log4cplus_helper.cpp
+    log4vendor.cpp
+    mutex.cpp
+	env_deal.cpp)
+
+
+rvc_set_win_dll_ver(${MODULE_PREFIX} ${RAW_VERSION_STRING})
+
+conan_cmake_run(REQUIRES log4cplus/1.2.1@LR04.02_ThirdParty/stable
+    BASIC_SETUP CMAKE_TARGETS
+    BUILD missing)
+
+add_library(${MODULE_NAME} SHARED ${${MODULE_PREFIX}_SRCS})
+target_include_directories(${MODULE_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
+set_target_properties(${MODULE_NAME} PROPERTIES COMPILE_DEFINITIONS "LIBLOG4VENDOR_EXPORTS")
+set_target_properties(${MODULE_NAME} PROPERTIES DEBUG_POSTFIX "d")
+
+if(MSVC)
+list(APPEND OTHER_LIBS Psapi)
+endif(MSVC)
+target_link_libraries(${MODULE_NAME} CONAN_PKG::log4cplus ${OTHER_LIBS})
+

+ 52 - 0
DevAdapter/self/liblog4vendor/env_deal.cpp

@@ -0,0 +1,52 @@
+#include "StdAfx.h"
+#include "env_deal.h"
+#include "log4vendor.h"
+
+
+namespace cmb {
+
+	env_deal::env_deal(const std::string& name):str_(name)
+	{
+	}
+
+	bool env_deal::set(const std::string& value)
+	{
+		DWORD dwResult = SetEnvironmentVariableA(str_.c_str(), value.c_str());
+		return (dwResult != 0);
+	}
+
+	bool env_deal::get(std::string& value)
+	{
+		bool res = false;
+		DWORD dwSize;
+		value.clear();
+		dwSize = GetEnvironmentVariableA(str_.c_str(), NULL, 0);
+		if(dwSize > 0) {
+			char* buf = new char[dwSize+1];
+			if(buf == NULL) {
+				return false;
+			}
+			memset(buf, '\0', sizeof(char)*(dwSize+1));
+			dwSize = GetEnvironmentVariableA(str_.c_str(), buf, dwSize);
+			if(dwSize > 0) {
+				value = buf;
+				res = true;
+			}
+			delete[] buf;
+		}
+		return res;
+	}
+
+	env_deal::~env_deal(void)
+	{
+	}
+
+	bool env_log_config::retrieve_env_value()
+	{
+		env_deal("VENDOR_RECODE_TYPE").get(record_type);
+		env_deal("VENDOR_RECODE_LEVEL").get(record_level);
+		env_deal("VENDOR_DLL_NAME").get(module_name);
+		env_deal("VENDOR_LOG_PATH").get(record_path);
+		return true;
+	}
+}

+ 37 - 0
DevAdapter/self/liblog4vendor/env_deal.h

@@ -0,0 +1,37 @@
+#ifndef _VTM_ENV_DEAL_H_
+#define _VTM_ENV_DEAL_H_
+
+#pragma once
+
+#include <Windows.h>
+#include <string>
+
+namespace cmb {
+
+	class env_deal
+	{
+	public:
+		env_deal(const std::string& name);
+		bool set(const std::string& value);
+		bool get(std::string& value);
+		~env_deal(void);
+	private:
+		std::string str_;
+	};
+
+	class env_log_config 
+	{
+	public:
+		std::string record_level;
+		std::string record_type;
+		std::string record_path;
+		std::string module_name;
+
+		bool retrieve_env_value();
+	};
+}
+
+
+
+#endif //_VTM_ENV_DEAL_H_
+

+ 108 - 0
DevAdapter/self/liblog4vendor/liblog4vendor.cpp

@@ -0,0 +1,108 @@
+// liblog4vendor.cpp : 定义 DLL 应用程序的导出函数。
+//
+
+#include "liblog4vendor.h"
+#include <stdio.h>
+#include <Psapi.h>
+
+BOOL GetCurProcessPath(char szPath[], DWORD dwPathSize);
+
+#define CUR_PROCESS_NAME "sphost.exe"
+
+static HMODULE gModule = NULL;
+static INT IsSphostExe = -1;
+
+ /*!
+ * @brief detect current process is created by VTM
+ * @return : TRUE: created by VTM; FALSE: created by vendor
+ * TODO: need to enforce it for safety.
+ */
+EXTERN_C BOOL IsVTMProcess()
+{
+	if(IsSphostExe == -1) {
+		BOOL retVal = FALSE;
+		char szPath[MAX_PATH] = {'\0'};
+		DWORD dwPathSize = MAX_PATH;
+		if(GetCurProcessPath(szPath, dwPathSize)) {
+			char* pos = strstr(szPath, CUR_PROCESS_NAME);
+			dwPathSize = strlen(szPath);
+			if(pos != NULL && ((pos-szPath) + strlen(CUR_PROCESS_NAME)) == dwPathSize) {
+				IsSphostExe = TRUE;
+			} else {
+				IsSphostExe = FALSE;
+			}
+		} else {
+			/*If failed, regard it as VTM environment.*/
+			IsSphostExe = TRUE;
+		}
+	}
+	return IsSphostExe;
+}
+
+EXTERN_C BOOL GetCurFileVersion(char szVerion[], DWORD dwVerionSize)
+{
+	HRSRC hsrc=FindResourceA(gModule, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);
+	HGLOBAL hgbl = LoadResource(gModule, hsrc);
+	BYTE *pBt = (BYTE *)LockResource(hgbl);
+	VS_FIXEDFILEINFO* pFinfo = (VS_FIXEDFILEINFO*)(pBt + 40);
+	sprintf_s(szVerion, dwVerionSize, "%d.%d.%d.%d",
+		(pFinfo->dwFileVersionMS >> 16) & 0xFF,
+		(pFinfo->dwFileVersionMS) & 0xFF,
+		(pFinfo->dwFileVersionLS >> 16) & 0xFF,
+		(pFinfo->dwFileVersionLS) & 0xFF);
+
+	return TRUE;
+}
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+	DWORD  ul_reason_for_call,
+	LPVOID lpReserved
+	)
+{
+	switch (ul_reason_for_call)
+	{
+	case DLL_PROCESS_ATTACH:
+		gModule = hModule;
+		IsVTMProcess();
+		break;
+	case DLL_THREAD_ATTACH:
+	case DLL_THREAD_DETACH:
+	case DLL_PROCESS_DETACH:
+		break;
+	}
+	return TRUE;
+}
+
+BOOL GetCurProcessPath(char szPath[], DWORD dwPathSize)
+{
+	ZeroMemory(szPath, sizeof(char)*dwPathSize);
+	const DWORD PID = GetCurrentProcessId();
+	HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 
+		FALSE, PID);
+
+	if (hProcess == NULL) {
+		return FALSE;
+	}
+	
+	if (GetModuleFileNameExA(hProcess, (HMODULE)0, szPath, dwPathSize) == 0) {
+		printf("GetModuleFileNameExA failed: %d\n", GetLastError());
+		DWORD dwSize = dwPathSize;
+		if(QueryFullProcessImageNameA(hProcess, 0, szPath, &dwSize) == 0)
+		{
+			printf("QueryFullProcessImageNameA failed: %d\n", GetLastError());
+			if (!GetProcessImageFileNameA(hProcess, szPath, dwSize)) {
+				printf("GetProcessImageFileNameA failed: %d\n", GetLastError());
+				CloseHandle(hProcess);
+				return FALSE;
+			}
+		}
+	}
+	
+	CloseHandle(hProcess);
+
+	printf("process image name: %s\n", szPath);
+	return TRUE;
+
+}
+
+

+ 14 - 0
DevAdapter/self/liblog4vendor/liblog4vendor.h

@@ -0,0 +1,14 @@
+#pragma once
+
+#include <SDKDDKVer.h>
+
+#ifndef WIN32_LEAN_AND_MEAN
+    #define WIN32_LEAN_AND_MEAN             //  从 Windows 头文件中排除极少使用的信息
+#endif
+
+// Windows 头文件:
+#include <windows.h>
+
+EXTERN_C BOOL IsVTMProcess();
+
+EXTERN_C BOOL GetCurFileVersion(char szVerion[], DWORD dwVerionSize);

BIN
DevAdapter/self/liblog4vendor/liblog4vendor.rc


+ 467 - 0
DevAdapter/self/liblog4vendor/log4cplus_helper.cpp

@@ -0,0 +1,467 @@
+#include "log4cplus_helper.h"
+#include <iostream>
+#include <string>
+
+#if defined(_WIN32) && defined (LOG4CPLUS_HAVE_WIN32_CONSOLE)
+#include <log4cplus/win32consoleappender.h>
+#define WIN32_CONSOLE 1
+#endif
+
+#if defined(ANDROID)
+#include <android/log.h>
+static const char* TAG = "lib";
+#endif
+
+using namespace log4cplus;
+using namespace log4cplus::helpers;
+
+#define MAX_BUFFER_LENGTH 4096
+
+#define LOG4PLUS_LOG(TYPE, LOGGER, msg) \
+	LOG4CPLUS_##TYPE(LOGGER, msg);
+
+
+static inline vtm_string w2s(const std::wstring wstr)
+{
+	char* str = NULL;
+	int n = ::WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, NULL, 0, NULL, NULL);
+	if (n > 0) {
+		str = new char[n+1];
+		if(str == NULL) {
+			return vtm_string();
+		}
+		std::memset(str, 0, sizeof(char)*(n+1));
+		::WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), -1, &str[0], n, NULL, NULL);
+		vtm_string strr(str);
+		delete str;
+		return strr;
+	}
+	return vtm_string();
+}
+
+namespace cmb {
+
+	log4cplus_helper* log4cplus_helper::_instance = NULL;
+	mutex log4cplus_helper::_mutex;
+
+	log4cplus_helper::log4cplus_helper(void)
+		:_append_console(NULL),_append_file(NULL),_append_socket(NULL),_append_none(NULL)
+		,_socket_send_running(false)
+	    ,_initialized(false),_append_type(0),_log_server_port(0),_log_listen_port(0)
+		,_initilzed_zip(false),_cur_upload_log(""),_cur_upload_offset(0),_log_level(NOT_SET_LOG_LEVEL)
+	{
+		_log_dir.clear();
+		_log_server_ip.clear();
+		_log_server_port = 0;
+		_log_key_name = "vtm";
+	}
+
+	log4cplus_helper::~log4cplus_helper(void)
+	{
+		uninit();
+		while(!_zip_logs.empty()) {
+			_zip_logs.pop();
+		}
+	}
+
+	log4cplus_helper* log4cplus_helper::get_instance()
+	{
+		if(_instance == NULL) {
+			unique_lock lock_(_mutex);
+			if(_instance == NULL) {
+				_instance = new log4cplus_helper();
+			}
+		}
+		return _instance;
+	}
+
+	bool log4cplus_helper::init(const char* name)
+	{
+		if(_initialized) {
+			return true;
+		}
+		if(name == NULL || strlen(name) == 0)
+			return false;
+
+		if((_append_type & log_append_file) && _log_dir.empty()) {
+			return false;
+		}
+
+		_log_key_name = name;
+		log4cplus::initialize();
+#ifdef _DEBUG
+		LogLog::getLogLog()->setInternalDebugging(true);
+#else
+		LogLog::getLogLog()->setInternalDebugging(false);
+#endif
+		log4cplus::Logger& logger = get_logger();
+		logger.setLogLevel(_log_level);
+		
+		if ((_append_type & log_append_console) == log_append_console)
+		{
+			_append_console = new ConsoleAppender(false, true);
+			log4cplus::tstring pattern = LOG4CPLUS_TEXT("%d{%H:%M:%S,%Q} [%t] %-5p %c{2} - %m%n");
+			_append_console->setLayout( std::auto_ptr<Layout>(new PatternLayout(pattern)) );
+			logger.addAppender(_append_console);
+			_append_console->setName(LOG4CPLUS_TEXT("console"));
+		}
+		if ((_append_type & log_append_file) == log_append_file)
+		{
+			tostringstream propsOStream;
+			propsOStream << LOG4CPLUS_TEXT("CreateDirs=true\n")
+				<< LOG4CPLUS_TEXT("Append=true\n")
+				<< LOG4CPLUS_TEXT("MaxHistory=999\n")
+				<< LOG4CPLUS_TEXT("ImmediateFlush=true\n")
+				<< LOG4CPLUS_TEXT("RollOnClose=false\n");
+			vtm_string log_path(_log_dir);
+			assert(!log_path.empty());
+			log_path += name;
+			log_path += LOG4CPLUS_TEXT("\\");		
+			tstring str(LOG4CPLUS_TEXT("FilenamePattern="));
+			str += log_path;
+			str += LOG4CPLUS_TEXT("%d{yyyyMMdd}.log\n");
+			propsOStream << str; 
+			tistringstream propsStream (propsOStream.str());
+			helpers::Properties props (propsStream);
+			_append_file = new TimeBasedRollingFileAppender(props);
+			log4cplus::tstring pattern = LOG4CPLUS_TEXT("[%D{%H:%M:%S.%Q}][%-5p][%t] %m %n");
+			//<%x> - %X{key}
+			_append_file->setLayout( std::auto_ptr<Layout>(new PatternLayout(pattern)) );
+			logger.addAppender(_append_file);
+			_append_file->setName(LOG4CPLUS_TEXT("file_log"));
+		}
+		if (_append_type <= log_append_none || _append_type > log_append_all)
+		{
+			_append_none = new NullAppender();
+			_append_none->setLayout( std::auto_ptr<Layout>(new log4cplus::TTCCLayout()) ); 
+			logger.addAppender(_append_none);
+			_append_none->setName(LOG4CPLUS_TEXT("none_log"));
+		}
+		_initialized = true;
+		return _initialized;
+	}
+
+
+	void log4cplus_helper::config_remote_logger(const char* remote_name)
+	{
+		LOG4VTM(INFO, "Enter config remote logger: " << remote_name);
+		if(remote_name == NULL || strlen(remote_name) == 0) {
+			LOG4VTM(ERROR, "remote log name is empty, config remote logger failed!");
+			return;
+		}
+		if(strcmp(remote_name, _log_key_name.c_str()) == 0) {
+			LOG4VTM(WARN, "the remote name is the same with the local key name, use local config.");
+			return;
+		}
+		log4cplus::Logger logger = log4cplus::Logger::getInstance(LOG4CPLUS_TEXT(remote_name));
+		//todo
+		logger.setLogLevel(log4cplus::TRACE_LOG_LEVEL);
+		if ((_append_type & log_append_console) == log_append_console)
+		{
+#ifdef WIN32_CONSOLE
+			static SharedAppenderPtr append_1(new Win32ConsoleAppender(false, false,
+				FOREGROUND_GREEN | FOREGROUND_INTENSITY));
+#else
+			static SharedAppenderPtr append_1(new ConsoleAppender(false, true));
+#endif
+			log4cplus::tstring pattern = LOG4CPLUS_TEXT("%d{%H:%M:%S,%Q} [%t] %-5p %c{2} - %m%n");
+			append_1->setLayout( std::auto_ptr<Layout>(new PatternLayout(pattern)) );
+			logger.addAppender(append_1);
+			append_1->setName(LOG4CPLUS_TEXT("android_console"));
+		}
+		if ((_append_type & log_append_file) == log_append_file)
+		{
+			tostringstream propsOStream;
+			propsOStream << LOG4CPLUS_TEXT("CreateDirs=true\n")
+				<< LOG4CPLUS_TEXT("Append=true\n")
+				<< LOG4CPLUS_TEXT("MaxHistory=999\n")
+				<< LOG4CPLUS_TEXT("ImmediateFlush=true\n")
+				<< LOG4CPLUS_TEXT("RollOnClose=false\n");
+			vtm_string log_path(_log_dir);
+			assert(!log_path.empty());
+			log_path += remote_name;
+			log_path += "\\";
+			tstring str(LOG4CPLUS_TEXT("FilenamePattern="));
+			str += log_path;
+			str += LOG4CPLUS_TEXT("%d{yyyyMMdd}.log\n");
+			propsOStream << str;
+			tistringstream propsStream (propsOStream.str());
+			helpers::Properties props (propsStream);
+			static SharedAppenderPtr append_2(new TimeBasedRollingFileAppender(props));
+			log4cplus::tstring pattern = LOG4CPLUS_TEXT("[%D{%H:%M:%S.%Q}][%-5p] %m %n");
+			append_2->setLayout( std::auto_ptr<Layout>(new PatternLayout(pattern)) );
+			logger.addAppender(append_2);
+			append_2->setName(LOG4CPLUS_TEXT("android_file_log"));
+		}
+	}
+
+
+    int log4cplus_helper::run_log_sender(const vtm_string& ip,const unsigned short port)
+    {
+        unique_lock lock_(_mutex_4_update_socket);
+        LOG4VTM(INFO, "Enter run_log_sender...");
+        if(!_initialized) {
+            LOG4VTM(WARN, "log4cplus helper has not been initialized");
+            return -1;
+        }
+
+        if ((_append_type & log_append_socket) == log_append_socket)
+        {
+            if(ip == _log_server_ip && _log_server_port == port) {
+                LOG4VTM(WARN, "log4cplus has been set as the same server ip and port!");
+                return -1;
+            }
+
+            if (!ip.empty() && port != 0) {
+                if(_socket_send_running) {
+                    LOG4VTM(INFO, "remove appender");
+                    get_logger().removeAppender(_append_socket);
+                    _append_socket->close();
+                    _append_socket = NULL;
+                }
+                LOG4VTM(INFO, "new socket appender");
+                tostringstream propsOStream;
+                propsOStream << LOG4CPLUS_TEXT("Appender=log4cplus::SocketAppender\n")
+                             << LOG4CPLUS_TEXT("QueueLimit=10000\n");
+                {
+                    propsOStream << LOG4CPLUS_TEXT("Appender.host=");
+                    propsOStream << ip << "\n";
+                }
+                {
+                    propsOStream << LOG4CPLUS_TEXT("Appender.port=");
+                    propsOStream << port << "\n";
+                }
+                {
+                    propsOStream << LOG4CPLUS_TEXT("Appender.ServerName=");
+                    propsOStream << _log_key_name << "\n";
+                }
+                tistringstream propsStream (propsOStream.str());
+                helpers::Properties props (propsStream);
+                _append_socket = new AsyncAppender(props);
+                LOG4VTM(INFO, "new socket appender done");
+                _append_socket->setLayout( std::auto_ptr<Layout>(new log4cplus::TTCCLayout()) );
+                _append_socket->setName(LOG4CPLUS_TEXT("socket_log"));
+                LOG4VTM(INFO, "add appender");
+                get_logger().addAppender(_append_socket);
+                LOG4VTM(INFO, "add appender done");
+                _socket_send_running = true;
+                _log_server_ip = ip;
+                _log_server_port = port;
+                LOG4VTM(INFO, "update log sender successfully: " << ip << "::" << port);
+                return 0;
+            } else {
+                LOG4VTM(ERROR, "the remote log ip or port are not config !");
+				return -1;
+            }
+
+        } else {
+            LOG4VTM(ERROR, "the current log type is not supported ! " << _append_type);
+			return -1;
+        }
+		return 0;
+    }
+
+	void log4cplus_helper::uninit()
+	{
+		if(_initialized) {
+			get_logger().removeAllAppenders();
+			_append_console = NULL;
+			_append_file = NULL;
+			_append_none = NULL;
+			_append_socket = NULL;
+			log4cplus::Logger::shutdown();
+			_initialized = false;
+		}
+	}
+
+	std::ostream& log4cplus_helper::stream()
+	{
+		LOG4CPLUS_MACRO_INSTANTIATE_OSTRINGSTREAM (_log4cplus_buf);
+		return _log4cplus_buf;
+	}
+
+	void log4cplus_helper::trace(const vtm_string& text)
+	{
+		if(_initialized) {
+			LOG4PLUS_LOG(TRACE, get_logger(), text.c_str());
+		}
+	}
+
+	void log4cplus_helper::trace(const char* text)
+	{
+		if(_initialized) {
+			LOG4PLUS_LOG(TRACE, get_logger(), text);
+		}
+	}
+
+	void log4cplus_helper::info(const vtm_string& text)
+	{
+		if(_initialized) {
+			LOG4PLUS_LOG(INFO, get_logger(), text.c_str());
+		}
+	}
+
+	void log4cplus_helper::info(const char* text)
+	{
+		if(_initialized) {
+			LOG4PLUS_LOG(INFO, get_logger(), text);
+		}
+	}
+
+	void log4cplus_helper::debug(const vtm_string& text)
+	{
+#if !defined(NDEBUG)
+		if(_initialized) {
+			LOG4PLUS_LOG(INFO, get_logger(), text.c_str());
+		}
+#endif //!defined(NDEBUG)
+	}
+
+	void log4cplus_helper::debug(const char* text)
+	{
+#if !defined(NDEBUG)
+		if(_initialized) {
+			LOG4PLUS_LOG(DEBUG, get_logger(), text);
+		}
+#endif //!defined(NDEBUG)
+	}
+
+	void log4cplus_helper::warn(const vtm_string& text)
+	{
+		if(_initialized) {
+			LOG4PLUS_LOG(WARN, get_logger(), text.c_str());
+		}
+	}
+
+	void log4cplus_helper::warn(const char* text)
+	{
+		if(_initialized) {
+			LOG4PLUS_LOG(WARN, get_logger(), text);
+		}
+	}
+
+	void log4cplus_helper::error(const vtm_string& text)
+	{
+		if(_initialized) {
+			LOG4PLUS_LOG(ERROR, get_logger(), text.c_str());
+		}
+	}
+
+	void log4cplus_helper::error(const char* text)
+	{
+		if(_initialized) {
+			LOG4PLUS_LOG(ERROR, get_logger(), text);
+		}
+	}
+
+	void log4cplus_helper::fatal(const vtm_string& text)
+	{
+		if(_initialized) {
+			LOG4PLUS_LOG(FATAL, get_logger(), text.c_str());
+		}
+	}
+
+	void log4cplus_helper::fatal(const char* text)
+	{
+		if(_initialized) {
+			LOG4PLUS_LOG(FATAL, get_logger(), text);
+		}
+	}
+
+	vtm_string log4cplus_helper::format(const char *ft, ...)
+	{
+		va_list arg;
+		va_start (arg, ft);
+		vtm_string formatted = format(ft, arg);
+		return formatted;
+	}
+
+	vtm_string log4cplus_helper::format(const char *ft,va_list& arg)
+	{
+		int len = 0;
+		vtm_string formatted = "";
+		char* buffer = NULL;
+		len =  _vscprintf( ft, arg ) + 1;
+		buffer = (char*)malloc( len * sizeof(char) );
+		len = vsprintf_s(buffer,len,ft, arg);
+		formatted = buffer ;
+		free(buffer);
+		return formatted;
+	}
+
+	void log4cplus_helper::log(const char *file_name, const char *func_name, int line,
+		const char* ft, int type /*= log_level_debug*/)
+	{
+		std::stringstream sstream;
+		sstream << file_name << " " << func_name << " " << line << " " << ft << std::endl;
+		switch(type) {
+		case log_level_debug:
+			debug(sstream.str());
+			break;
+		case log_level_trace:
+			trace(sstream.str());
+			break;
+		case log_level_info:
+			info(sstream.str());
+			break;
+		case log_level_warn:
+			warn(sstream.str());
+			break;
+		case log_level_error:
+			error(sstream.str());
+			break;
+		case log_level_fatal:
+			fatal(sstream.str());
+			break;
+		default:
+			trace(sstream.str());
+			break;
+		}
+		return;
+	}
+
+	void log4cplus_helper::log(int log_level, const vtm_string& text)
+	{
+		switch (log_level) {
+			case CMB_LOG_TRACE:
+				trace(text);
+				break;
+			case CMB_LOG_DEBUG:
+				debug(text);
+				break;
+			case CMB_LOG_INFO:
+				info(text);
+				break;
+			case CMB_LOG_WARN:
+				warn(text);
+				break;
+			case CMB_LOG_ERROR:
+				error(text);
+				break;
+			case CMB_LOG_FATAL:
+				fatal(text);
+				break;
+			default:
+				trace(text);
+				break;
+		}
+		return;
+	}
+
+	void log4cplus_helper::log(const char *file_name, const char *func_name, int line, 
+		int type ,const char *ft /*= ""*/, ...)
+	{
+		va_list arg;
+		va_start (arg, ft);
+		vtm_string formatted = format(ft, arg);
+		va_end (arg);
+		log(file_name, func_name, line, formatted.c_str(),type);
+	}
+
+	void log4cplus_helper::logw(int log_level, const std::wstring& wtext)
+	{
+		auto text = ::w2s(wtext);
+		log(log_level, text);
+	}
+
+}

+ 175 - 0
DevAdapter/self/liblog4vendor/log4cplus_helper.h

@@ -0,0 +1,175 @@
+#ifndef _VTM_LOG4CPLUS_HELPER_H_
+#define _VTM_LOG4CPLUS_HELPER_H_
+
+#pragma once
+
+#include "log4vendor.h"
+#include <cstdint>
+#include <iostream>
+#include <set>
+#include <queue>
+
+#include <log4cplus/consoleappender.h>
+#include <log4cplus/fileappender.h>
+#include <log4cplus/socketappender.h>
+#include <log4cplus/asyncappender.h>
+#include <log4cplus/nullappender.h>
+#include <log4cplus/appender.h>
+#include <log4cplus/layout.h>
+#include <log4cplus/logger.h>
+#include <log4cplus/ndc.h>
+#include <log4cplus/helpers/loglog.h>
+#include <log4cplus/streams.h>
+#include <log4cplus/loggingmacros.h>
+#include <log4cplus/configurator.h>
+
+
+#include "mutex.h"
+
+namespace cmb {
+
+	enum cpluslog_level
+	{
+		log_level_debug = 0,
+		log_level_trace,
+		log_level_info,
+		log_level_warn,
+		log_level_error,
+		log_level_fatal,
+		log_level_end
+	};
+
+	enum cpluslog_append_type
+	{
+		log_append_none = 0,
+		log_append_console = 1,
+		log_append_file = 2,
+		log_append_console_file = 3,
+		log_append_socket = 4,
+		log_append_console_socket = 5,
+		log_append_file_socket = 6,
+		log_append_all = 7
+	};
+
+	class log4cplus_helper : public log4vendor
+	{
+	public:
+		~log4cplus_helper(void);
+		static log4cplus_helper* get_instance();
+		bool init(const char* name);
+		void uninit();
+		std::ostream& stream();
+
+		void trace(const vtm_string& text);
+		void info(const vtm_string& text);
+		void debug(const vtm_string& text);
+		void warn(const vtm_string& text);
+		void error(const vtm_string& text);
+		void fatal(const vtm_string& text);
+
+		void trace(const char* text);
+		void info(const char* text);
+		void debug(const char* text);
+		void warn(const char* text);
+		void error(const char* text);
+		void fatal(const char* text);
+
+		bool set_log_append_type(int type) {
+			if((type & log_append_console) || (type & log_append_file) || (type & log_append_socket)) {
+				_append_type = type;
+				return true;
+			}
+			return false;
+		}
+
+		 /*!
+		 * @brief 设置日志文件存储的路径文件夹
+		 * @param[in] 存储的文件夹路径,兼容不加 '\\' 的情况  
+		 * @return : 
+		 */
+		bool set_log_dir(const vtm_string& log_file) {
+
+			vtm_string tmp(log_file);
+			if(tmp.empty()) 
+				return false;
+			if(tmp[tmp.size()-1] != '\\' && tmp[tmp.size()-1] != '/') {
+				tmp.push_back('\\');
+			}
+			_log_dir = tmp;
+			return true;
+		}
+
+		bool set_log_level(const int level) {
+			const int ll = level * 10000;
+			if(ll < 0 || ll > log4cplus::OFF_LOG_LEVEL) {
+				return false;
+			}
+			_log_level = ll;
+			return true;
+		}
+
+		void update_map_value(const vtm_string& value) {
+			if(!value.empty()) {
+				log4cplus::getMDC ().put("key", value);
+			}
+		}
+
+		vtm_string get_map_value() {
+			vtm_string value("");
+			if(!log4cplus::getMDC().get(&value, "key")) {
+				return vtm_string("");
+			}
+			return value;
+		}
+		int run_log_sender(const vtm_string& ip, const unsigned short port);
+
+		vtm_string format(const char *ft, ...);
+		vtm_string format(const char *ft,va_list& arg);
+
+		void log( const char *file_name, const char *func_name, int line, const char* ft, int type = log_level_debug);
+		void log( const char *file_name, const char *func_name, int line, int type ,const char *ft = "", ...);
+		void log(int log_level, const vtm_string& text);
+
+		void logw(int log_level, const std::wstring& wtext);
+
+		log4cplus::Logger get_logger() {
+			return log4cplus::Logger::getInstance(LOG4CPLUS_TEXT(_log_key_name.c_str()));
+		}
+	private:
+		static log4cplus_helper* _instance;
+		log4cplus_helper(void);
+
+		void config_remote_logger(const char* remote_name);
+
+		log4cplus::helpers::SharedObjectPtr<log4cplus::Appender> _append_console;
+		log4cplus::helpers::SharedObjectPtr<log4cplus::Appender> _append_file;
+		log4cplus::helpers::SharedObjectPtr<log4cplus::Appender> _append_socket;
+		log4cplus::helpers::SharedObjectPtr<log4cplus::Appender> _append_none;
+
+		log4cplus::tstring _log_dir;
+		log4cplus::tstring _log_server_ip;
+		unsigned short _log_server_port;
+		vtm_string _log_client_key_name;
+
+		int _append_type;
+		vtm_string _log_key_name;
+		bool _socket_send_running;
+		static mutex _mutex;
+		bool _initialized;
+
+		unsigned short _log_listen_port;
+		mutex _mutex_4_update_socket;
+
+		bool _initilzed_zip;
+		std::queue<vtm_string> _zip_logs;
+		vtm_string _cur_upload_log;
+		uint64_t _cur_upload_offset;
+
+		int _log_level;
+	};
+}
+
+
+
+
+#endif //_VTM_LOG4CPLUS_HELPER_H_

+ 245 - 0
DevAdapter/self/liblog4vendor/log4vendor.cpp

@@ -0,0 +1,245 @@
+#include "log4vendor.h"
+#include "liblog4vendor.h"
+#include "log4cplus_helper.h"
+#include "env_deal.h"
+#include <vector>
+
+namespace cmb {
+
+	static bool log4plus_initialized = false;
+
+	class log4none : public log4vendor
+	{
+	public:
+		log4none() {}
+		void log(int log_level, const std::string& text) {/*do nothing.*/}
+		~log4none() {
+			/*通过全局静态变量的销毁函数中释放有效的日志实例对象*/
+			if(log4plus_initialized) {
+				LOG4VTM(INFO, "release log instance auto.");
+				log4cplus_helper::get_instance()->uninit();
+			}
+		}
+	};
+	/*在有效日志类实例没被初始化前返回的一个替代品*/
+	static log4none default_instance;
+
+
+	log4vendor* log4vendor::instance()
+	{
+		if(!log4plus_initialized)
+			return &default_instance;
+
+		return log4cplus_helper::get_instance();
+	}
+
+	std::vector<std::string> split(std::string str, char split_char)
+	{
+		std::vector<std::string> strs;
+		std::string::size_type pos1, pos2;
+		pos2 = str.find(split_char);
+		pos1 = 0;
+		while (std::string::npos != pos2) {
+
+			strs.push_back(str.substr(pos1, pos2 - pos1));
+			pos1 = pos2 + 1;
+			pos2 = str.find(split_char, pos1);
+		}
+		strs.push_back(str.substr(pos1));
+		return strs;
+	}
+	std::string toupper(const std::string str)
+	{
+		std::string dest;
+		dest.resize(str.size());
+		std::transform(str.begin(), str.end(), dest.begin(), ::toupper);
+		return dest;
+	}
+
+	/*从环境变量中提取的信息转换成日志配置结构体信息*/
+	static void env2config(const env_log_config& env, log_init_config* config)
+	{
+		config->dev_name = "";
+		config->log_dir = "";
+		config->log_level = CMB_LOG_LEVEL_OFF;
+		config->log_type = 0; /*OFF*/
+
+		//if(env.record_type.find("CONSOLE") != std::string::npos)
+		//	config->log_type |= CMB_LOG_TYPE_CONSOLE;
+		const std::string record_type = toupper(env.record_type);
+		if(record_type.find("FILE") != std::string::npos)
+			config->log_type |= CMB_LOG_TYPE_FILE;
+
+		/*get log level*/
+		const std::string record_level = toupper(env.record_level);
+		if(record_level.find("TRACE") != std::string::npos)
+			config->log_level = CMB_LOG_LEVEL_TRACE;
+		else if(record_level.find("INFO") != std::string::npos)
+			config->log_level = CMB_LOG_LEVEL_INFO;
+		else if(record_level.find("WARN") != std::string::npos)
+			config->log_level = CMB_LOG_LEVEL_WARN;
+		else if(record_level.find("ERROR") != std::string::npos)
+			config->log_level = CMB_LOG_LEVEL_ERROR;
+		else if(record_level.find("FATAL") != std::string::npos)
+			config->log_level = CMB_LOG_LEVEL_FATAL;
+		else if(record_level.find("ALL") != std::string::npos)
+			config->log_level = CMB_LOG_LEVEL_ALL;
+
+		auto dev_infos = split(env.module_name, '.');
+		//TODO: comfirm the name's validity. {DeviceName}.{VendorName}.{X}.{Y}.dll
+		if(dev_infos.size() == 5 && toupper(dev_infos[4]) == "DLL") {
+			config->dev_name = "vendor_";
+			config->dev_name += dev_infos[0];
+		}
+		config->log_dir = env.record_path;
+	}
+
+
+	void log4vendor::init(const log_init_config& config, std::string& ret_msg)
+	{
+		ret_msg.clear();
+		std::string env_string = "[RVC] ";
+		log_init_config* lhs = const_cast<log_init_config*>(&config);
+		log_init_config log_env_config;
+		std::string instance_name;
+
+		if(log4plus_initialized) {
+			assert(log4vendor::instance() != &default_instance);
+			ret_msg = "WARN: log instance has been initialized.";
+			goto error_point;
+		}
+
+		if(IsVTMProcess()) {
+			ret_msg = env_string + "INFO: vtm runtime, it's VTMers' responsibility to do initialize job.";
+			env_log_config log_config;
+			if(log_config.retrieve_env_value()) {
+				env2config(log_config, &log_env_config);
+				lhs = &log_env_config;
+				if(!log_config.module_name.empty()) {
+					env_string = log_config.module_name;
+				}
+			} else {
+				ret_msg = env_string + "WARN: vtm runtime, retrieve config failed.";
+				goto error_point;
+			}
+		} else {
+			env_string = "";
+		}
+
+		if(!log4cplus_helper::get_instance()->set_log_append_type(lhs->log_type)) {
+			ret_msg = env_string + "ERROR: set log type failed.";
+			goto error_point;
+		}
+
+		if(!log4cplus_helper::get_instance()->set_log_level(lhs->log_level)) {
+			ret_msg = env_string + "ERROR: set log level failed.";
+			goto error_point;
+		}
+
+		if(!log4cplus_helper::get_instance()->set_log_dir(lhs->log_dir)) {
+			ret_msg = env_string + "ERROR: set log dir failed.";
+			goto error_point;
+		}
+
+		if(!log4cplus_helper::get_instance()->init(lhs->dev_name.c_str())) {
+			ret_msg = env_string + "ERROR: real init failed.";
+			goto error_point;
+		}
+		instance_name = lhs->dev_name;
+		if(!env_string.empty()) {
+			instance_name = env_string;
+		}
+
+		/*提前在这里赋值,以便让 LOG4VTM 宏生效*/
+		log4plus_initialized = true;
+
+		LOG4VTM(INFO, "==============Log4Vendor(" << instance_name << ") start==============");
+		LOG4VTM(INFO, "process id: " << GetCurrentProcessId());
+		{
+			char ver[128] = {'\0'};
+			DWORD sz = 128;
+			GetCurFileVersion(ver, sz);
+			LOG4VTM(INFO, "log4vendor instance' s version: " << ver);
+		}
+
+		
+		return;
+
+error_point:
+
+		std::string ps = ret_msg + "\n";
+		OutputDebugStringA(ps.c_str());
+	}
+
+	/*获取输出字符串流引用对象,不自己定义,从开源库中获取会比较安全*/
+	std::basic_ostringstream<char>& log4vendor::get_oss()
+	{
+		LOG4CPLUS_MACRO_INSTANTIATE_OSTRINGSTREAM(var);
+		return var;
+	}
+
+	//////////////////////////////////////////////////////////////////////////
+
+		//class log4vendor_tracer::
+
+
+	log4vendor_tracer::log4vendor_tracer(const char* message, const char* fileName, int nLine)
+		:m_pszMes(message), m_pszFileN(fileName), m_nLine(nLine), m_pnRet(NULL), m_pDwRet(NULL), m_retType(-1)
+	{
+		std::ostringstream str;
+		str << "==> Enter {" << m_pszMes << "}, file: {" << m_pszFileN << "}, line: {" << m_nLine << "}.";
+		log4cplus_helper::get_instance()->trace(str.str());
+	}
+	log4vendor_tracer::log4vendor_tracer(const char* message, const char* fileName, int nLine, int* pRet)
+		:m_pszMes(message), m_pszFileN(fileName), m_nLine(nLine)
+		, m_pnRet(pRet), m_pDwRet(NULL), m_pfRet(NULL), m_retType(0)
+	{
+		std::ostringstream str;
+		str << "==> Enter {" << m_pszMes << "}, file: {" << m_pszFileN << "}, line: {" << m_nLine << "}.";
+		log4cplus_helper::get_instance()->trace(str.str());
+	}
+	log4vendor_tracer::log4vendor_tracer(const char* message, const char* fileName, int nLine, unsigned long* pRet)
+		:m_pszMes(message), m_pszFileN(fileName), m_nLine(nLine)
+		, m_pnRet(NULL), m_pDwRet(pRet), m_pfRet(NULL), m_retType(1)
+	{
+		std::ostringstream str;
+		str << "==> Enter {" << m_pszMes << "}, file: {" << m_pszFileN << "}, line: {" << m_nLine << "}.";
+		log4cplus_helper::get_instance()->trace(str.str());
+	}
+	log4vendor_tracer::~log4vendor_tracer()
+	{
+		std::ostringstream str;
+		if(m_retType == 0)
+		{
+			str << "<== Leave {" << m_pszMes << "}, file: {" << m_pszFileN << "}, line: {" << m_nLine << "}, return: {" << *m_pnRet << "}.";
+		}
+		else if(m_retType == 1)
+		{
+			str << "<== Leave {" << m_pszMes << "}, file: {" << m_pszFileN << "}, line: {" << m_nLine << "}, return: {" << *m_pDwRet << "}.";
+		}
+		else if (m_retType == 2)
+		{
+			str << "<== Leave {" << m_pszMes << "}, file: {" << m_pszFileN << "}, line: {" << m_nLine << "}, return: {" << *m_pfRet << "}.";
+		}
+		else {
+			str << "<== Leave {" << m_pszMes << "}, file: {" << m_pszFileN << "}, line: {" << m_nLine << "}.";
+		}
+		log4cplus_helper::get_instance()->trace(str.str());
+	}
+
+	const char* log4vendor_tracer::_get_file_name(const char* file_path)
+	{
+		if(file_path == NULL || strlen(file_path) == 0) {
+			return "empty";
+		}
+		const char* backlash = strrchr(file_path, (int)('\\'));
+		if(backlash == NULL) {
+			backlash = strrchr(file_path, (int)('/'));
+		}
+		if(!backlash) {
+			return file_path;
+		}
+		return (backlash+1);
+	}
+}
+

+ 197 - 0
DevAdapter/self/liblog4vendor/log4vendor.h

@@ -0,0 +1,197 @@
+ /***********************************//**
+ * @file log4vendor.h
+ * @email guifaliao@gmail.com
+ * @version 0.0.0.1
+ * @date 2020-04-28
+ * @copyright China Merchants Bank Co.,Ltd All rights reserved
+ *
+ * @brief Log class for VTM device vendor for developing device adapter
+ * @details 
+ *	2020-4-28: strip log component from SpAgent Project and adjust it.
+ *  
+ **************************************/
+
+#ifndef _VTM_LOG4VENDOR_H_
+#define _VTM_LOG4VENDOR_H_
+
+#pragma once
+
+#include <sstream>
+#include <string>
+
+#ifdef _WIN32
+#ifdef LIBLOG4VENDOR_EXPORTS
+#define LOG4VENDOR_API __declspec(dllexport)
+#else
+#define LOG4VENDOR_API __declspec(dllimport)
+#endif
+#else
+#if ( defined(__GNUC__) &&  __GNUC__ >= 4 )
+#define LOG4VENDOR_API __attribute__((visibility("default")))
+#else
+#define LOG4VENDOR_API
+#endif
+#endif
+
+#ifdef UNICODE
+#error This version is not support {UNICODE} char set!!
+#define LOG4VTM_TEXT2(STRING) L##STRING
+typedef std::wstring vtm_string;
+typedef wchar_t vtm_char;
+#else
+#define LOG4VTM_TEXT2(STRING) STRING
+typedef std::string vtm_string;
+typedef char vtm_char;
+#endif // UNICODE
+#define LOG4VTM_TEXT(STRING) LOG4VTM_TEXT2(STRING)
+
+
+#define CMB_LOG_TYPE_CONSOLE 1   /*控制台输出*/
+#define CMB_LOG_TYPE_FILE    2   /*文件记录输出*/
+#define CMB_LOG_TYPE_SOCKET  4   /*TCP传输输出,暂未实现*/
+
+#define CMB_LOG_LEVEL_OFF     6  /*关闭任何日志输出*/
+#define CMB_LOG_LEVEL_FATAL   5  /*非常严重类型的日志输出*/
+#define CMB_LOG_LEVEL_ERROR   4  /*错误类型的日志输出*/
+#define CMB_LOG_LEVEL_WARN    3  /*告警类型的日志输出*/
+#define CMB_LOG_LEVEL_INFO    2  /*普通日志输出*/
+#define CMB_LOG_LEVEL_DEBUG   1  /*调试日志输出*/
+#define CMB_LOG_LEVEL_TRACE   0  /*跟踪函数进出等输出*/
+#define CMB_LOG_LEVEL_ALL     CMB_LOG_LEVEL_TRACE
+
+#define CMB_LOG_TRACE   1
+#define CMB_LOG_DEBUG   2
+#define CMB_LOG_INFO    3
+#define CMB_LOG_WARN    4
+#define CMB_LOG_ERROR   5
+#define CMB_LOG_FATAL   6
+//#define CMB_LOG_ASSERT  7
+
+#define CMB_INSTANTIATE_OSTRINGSTREAM(var)                              \
+	std::basic_ostringstream<char>& var                                 \
+	= cmb::log4vendor::get_oss()
+
+#define CMB_LOG_BODY(logLevel, logEvent)                                \
+	__pragma (warning (push))                                           \
+	__pragma (warning (disable:4127))                                   \
+    do {                                                                \
+        cmb::log4vendor* _l                                             \
+            = cmb::log4vendor::instance();                              \
+		CMB_INSTANTIATE_OSTRINGSTREAM (_log4cplus_buf);                 \
+		_log4cplus_buf << logEvent;                                     \
+        _l->log(logLevel, _log4cplus_buf.str());                        \
+    } while (0)                                                         \
+    __pragma (warning (pop))
+
+
+ /*!
+ * @brief 打印日志的函数,所有等级的日志打印均通过该宏调用实现
+ * @param[in]  
+ *		severity: 日志等级 TRACE, INFO, WARN, ERROR, FATAL, ASSERT
+ *		ostr:     要打印的内容,支持 << 连续输出
+ */
+#define LOG4VTM(severity, ostr)                                        \
+    CMB_LOG_BODY(CMB_LOG_ ## severity, ostr)
+
+ /*!
+ * @brief: 用于记录函数进出的宏定义,在进入目的函数时立即调用,在该函数退出时会打印日志
+/**/
+#define LOG4VTM_FUNCTION() cmb::log4vendor_tracer _FunctionTraceLogger(\
+	__FUNCTION__, cmb::log4vendor_tracer::_get_file_name(__FILE__), __LINE__)
+
+ /*!
+ * @brief 类似于 LOG4VTM_FUNCTION(),除外还添加一个入参用于打印返回值,注意该入参的生命周期为整个函数内!!
+ * @param[in]: pValue - 仅支持传入 int* 或 DWORD* 类型,在日志中会打印指针所存储的值
+ */
+#define TRACE4VTM_FUNCTION(pValue) cmb::log4vendor_tracer _FunctionTraceLogger(\
+	__FUNCTION__, cmb::log4vendor_tracer::_get_file_name(__FILE__), __LINE__, (pValue))
+
+
+namespace cmb {
+
+	struct log_init_config 
+	{
+		short log_type;       /*见上面 CMB_LOG_TYPE_FILE 等定义*/
+		short log_level;      /*见上面 CMB_LOG_TRACE 等定义*/
+		vtm_string dev_name;  /*硬件名称,用于作为子目录的区分*/
+		vtm_string  log_dir;  /*在 log_type 包含 CMB_LOG_TYPE_FILE 时,该参数才有效,用于记录日志的目录*/
+
+		log_init_config()
+			:log_type(CMB_LOG_TYPE_FILE)
+			,log_level(CMB_LOG_TRACE)
+			,dev_name(LOG4VTM_TEXT("VTM")),log_dir(LOG4VTM_TEXT("")){}
+	};
+
+	class LOG4VENDOR_API log4vendor
+	{
+	public:
+
+		static log4vendor* instance();
+
+		 /*!
+		 * @brief 在调用打印日志的相关宏时,请先调用此函数进行初始化,否则将不会打印任何形式的日志内容
+		 *
+		 * @param[in]  
+		 *		config: 日志初始化的配置参数
+		 *		ret_msg: 防止传入的参数有误,在必要的时候记录错误信息,供上层打印排查
+		 *		
+		 *	如传入的参数依次为:"PinPad", CMB_LOG_TYPE_FILE|CMB_LOG_TYPE_CONSOLE, "C:\\rvc\\dbg"
+		 *  那么将会日志记在 "C:\\rvc\\dbg\\PinPad\\{YYYYMMDD}.log" 内,并将支持控制台输出
+		 *		
+		 */
+		static void init(const log_init_config& config, vtm_string& ret_msg);
+
+		virtual void log(int log_level, const vtm_string& text) = 0;
+
+		static std::basic_ostringstream<char>& get_oss();
+		
+		//static std::basic_ostringstream<wchar_t>& get_woss();
+
+#ifdef LIBLOG4VENDOR_EXPORTS
+	public:
+#else
+	private:
+#endif
+		log4vendor() {}
+		virtual ~log4vendor(){}
+	private:
+		log4vendor(const log4vendor& rhs);
+	};
+
+	
+	//////////////////////////////////////////////////////////////////////////
+
+
+
+	class LOG4VENDOR_API log4vendor_tracer
+	{
+	public:
+
+		log4vendor_tracer(const char* message, const char* fileName, int nLine);
+		
+		log4vendor_tracer(const char* message, const char* fileName, int nLine, int* pRet);
+		
+		log4vendor_tracer(const char* message, const char* fileName, int nLine, unsigned long* pRet);
+		
+		~log4vendor_tracer();
+
+
+		static const char* _get_file_name(const char* file_path);
+
+	private:
+		
+		log4vendor_tracer (log4vendor_tracer const &);
+		log4vendor_tracer & operator = (log4vendor_tracer const &);
+
+		const char* m_pszMes;
+		const char* m_pszFileN;
+		int m_nLine;
+
+		int* m_pnRet;
+		unsigned long* m_pDwRet;
+		int* m_pfRet;
+		int m_retType;
+	};
+}
+
+#endif //_VTM_LOG4VENDOR_H_

+ 25 - 0
DevAdapter/self/liblog4vendor/mutex.cpp

@@ -0,0 +1,25 @@
+#include "mutex.h"
+
+namespace cmb {
+
+	mutex::mutex()
+	{
+		::InitializeCriticalSection(&csection_);
+	}
+
+	mutex::~mutex()
+	{
+		::DeleteCriticalSection(&csection_);
+	}
+
+	void mutex::lock()
+	{
+		::EnterCriticalSection(&csection_);
+	}
+
+	void mutex::unlock()
+	{
+		::LeaveCriticalSection(&csection_);
+	}
+
+}

+ 67 - 0
DevAdapter/self/liblog4vendor/mutex.h

@@ -0,0 +1,67 @@
+#pragma once
+
+#include <Windows.h>
+
+
+namespace cmb {
+
+	class noncopyable
+	{
+	protected:
+		noncopyable(){}
+		~noncopyable(){}
+	private:
+		noncopyable(const noncopyable&);
+		const noncopyable& operator=(const noncopyable&);
+
+	};
+
+	class mutex : private noncopyable
+	{
+		friend class condition;
+	public:
+		mutex();
+		~mutex();
+
+		void lock();
+		void unlock();
+
+	private:
+#if defined(_MSC_VER)
+		CRITICAL_SECTION csection_;
+#elif defined(__GNUC__)
+		pthread_mutex_t mutx_;
+#endif
+	};
+
+	class unique_lock : private noncopyable
+	{
+	public:
+		unique_lock(mutex& m) : mutex_(m)
+		{
+			mutex_.lock();
+			owns_ = true;
+		}
+		~unique_lock()
+		{
+			if (owns_)
+			{
+				mutex_.unlock();
+			}
+		}
+		void lock()
+		{
+			owns_ = true;
+			mutex_.lock();
+		}
+		void unlock()
+		{
+			owns_ = false;
+			mutex_.unlock();
+		}
+	private:
+		mutex& mutex_;
+		bool owns_;
+	};
+
+}

+ 14 - 0
DevAdapter/self/liblog4vendor/resource.h

@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by liblog4vendor.rc
+
+// жÔÏóµÄÏÂÒ»×éĬÈÏÖµ
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        101
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1001
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif

+ 8 - 0
DevAdapter/self/liblog4vendor/stdafx.cpp

@@ -0,0 +1,8 @@
+// stdafx.cpp : 只包括标准包含文件的源文件
+// liblog4vendor.pch 将作为预编译头
+// stdafx.obj 将包含预编译类型信息
+
+#include "stdafx.h"
+
+// TODO: 在 STDAFX.H 中
+// 引用任何所需的附加头文件,而不是在此文件中引用

+ 19 - 0
DevAdapter/self/liblog4vendor/stdafx.h

@@ -0,0 +1,19 @@
+// stdafx.h : 标准系统包含文件的包含文件,
+// 或是经常使用但不常更改的
+// 特定于项目的包含文件
+//
+
+#pragma once
+
+#include "targetver.h"
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN             //  从 Windows 头文件中排除极少使用的信息
+#endif // !WIN32_LEAN_AND_MEAN
+
+// Windows 头文件:
+#include <windows.h>
+
+
+
+// TODO: 在此处引用程序需要的其他头文件

+ 8 - 0
DevAdapter/self/liblog4vendor/targetver.h

@@ -0,0 +1,8 @@
+#pragma once
+
+// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。
+
+// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将
+// WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。
+
+#include <SDKDDKVer.h>

+ 8 - 0
DevAdapter/self/liblog4vendor/test/stdafx.cpp

@@ -0,0 +1,8 @@
+// stdafx.cpp : 只包括标准包含文件的源文件
+// test4log.pch 将作为预编译头
+// stdafx.obj 将包含预编译类型信息
+
+#include "stdafx.h"
+
+// TODO: 在 STDAFX.H 中
+// 引用任何所需的附加头文件,而不是在此文件中引用

+ 15 - 0
DevAdapter/self/liblog4vendor/test/stdafx.h

@@ -0,0 +1,15 @@
+// stdafx.h : 标准系统包含文件的包含文件,
+// 或是经常使用但不常更改的
+// 特定于项目的包含文件
+//
+
+#pragma once
+
+#include "targetver.h"
+
+#include <stdio.h>
+#include <tchar.h>
+
+#include <Windows.h>
+
+// TODO: 在此处引用程序需要的其他头文件

+ 8 - 0
DevAdapter/self/liblog4vendor/test/targetver.h

@@ -0,0 +1,8 @@
+#pragma once
+
+// 包括 SDKDDKVer.h 将定义可用的最高版本的 Windows 平台。
+
+// 如果要为以前的 Windows 平台生成应用程序,请包括 WinSDKVer.h,并将
+// WIN32_WINNT 宏设置为要支持的平台,然后再包括 SDKDDKVer.h。
+
+#include <SDKDDKVer.h>

+ 255 - 0
DevAdapter/self/liblog4vendor/test/test4log.cpp

@@ -0,0 +1,255 @@
+// test4log.cpp : 定义控制台应用程序的入口点。
+//
+
+#include "stdafx.h"
+#include <assert.h>
+#include <time.h>
+#include "log4vendor.h"
+#include <iostream>
+
+int testInt()
+{
+	int result = 0;
+	TRACE4VTM_FUNCTION(&result);
+	/*
+		...
+		...
+	*/
+	result = 95555;
+	/*
+		...
+		...
+	*/
+	return result;
+}
+
+int testDWORD()
+{
+	DWORD result = 0;
+	TRACE4VTM_FUNCTION(&result);
+	/*
+		...
+		...
+	*/
+	result = 4026531840; /* 0xF0000000 */
+	/*
+		...
+		...
+	*/
+	return result;
+}
+
+void testVoid()
+{
+	LOG4VTM_FUNCTION();
+	int count = 0;
+	return;
+}
+
+void logInitize_FileRecord()
+{
+	std::string err_msg;
+	cmb::log_init_config config;
+	config.dev_name =_T("PinPad");
+	config.log_type = CMB_LOG_TYPE_FILE;
+	config.log_level = CMB_LOG_LEVEL_ALL;
+	config.log_dir =_T("C:\\rvc\\dbg\\");
+
+	cmb::log4vendor::init(config, err_msg);
+	assert(err_msg.empty());
+
+	LOG4VTM(TRACE,_T("This is first TRACE type message."));
+	LOG4VTM(INFO,_T("This is first INFO type message."));
+	LOG4VTM(WARN,_T("This is first WARN type message."));
+	LOG4VTM(ERROR,_T("This is first ERROR type message."));
+	LOG4VTM(FATAL,_T("This is first FATAL type message."));
+}
+
+void logInitize_Console()
+{
+	std::string err_msg;
+	cmb::log_init_config config;
+	config.dev_name =_T("PinPad");
+	config.log_type = CMB_LOG_TYPE_FILE | CMB_LOG_TYPE_CONSOLE;
+	config.log_level = CMB_LOG_LEVEL_ALL;
+	config.log_dir =_T("C:\\rvc\\dbg\\");
+
+	cmb::log4vendor::init(config, err_msg);
+	std::cout << err_msg << std::endl;
+	assert(err_msg.empty());
+
+	LOG4VTM(TRACE,_T("This is first TRACE type message."));
+	LOG4VTM(INFO,_T("This is first INFO type message."));
+	LOG4VTM(WARN,_T("This is first WARN type message."));
+	LOG4VTM(ERROR,_T("This is first ERROR type message."));
+	LOG4VTM(FATAL,_T("This is first FATAL type message."));
+}
+
+void logInitize_SupportDirPathWithoutSlash()
+{
+	std::string err_msg;
+	cmb::log_init_config config;
+	config.dev_name =_T("PinPad");
+	config.log_type = CMB_LOG_TYPE_FILE;
+	config.log_level = CMB_LOG_LEVEL_ALL;
+	config.log_dir =_T("C:\\rvc\\dbg");
+
+	cmb::log4vendor::init(config, err_msg);
+	assert(err_msg.empty());
+}
+
+void logInitize_SupportDiffLogLevel_ERROR()
+{
+	std::string err_msg;
+	cmb::log_init_config config;
+	config.dev_name =_T("PinPad");
+	config.log_type = CMB_LOG_TYPE_FILE;
+	config.log_level = CMB_LOG_LEVEL_ERROR;
+	config.log_dir =_T("C:\\rvc\\dbg\\");
+
+	cmb::log4vendor::init(config, err_msg);
+	assert(err_msg.empty());
+
+	LOG4VTM(TRACE,_T("The TRACE type message would not record!"));
+	LOG4VTM(INFO,_T("The INFO type message would not record!"));
+	LOG4VTM(WARN,_T("The WARN type message would not record!"));
+	LOG4VTM(ERROR,_T("This is first ERROR type message."));
+	LOG4VTM(FATAL,_T("This is first FATAL type message."));
+}
+
+#include <process.h>
+
+#define random(x) (rand()%x)
+int get_random(int reft, int right)
+{
+	int c = random(right);
+	while(c < reft) {
+		c = random(right);
+	}
+	return c;
+}
+
+UINT WINAPI thread1(LPVOID param)
+{
+	int i = (int)param;
+	TRACE4VTM_FUNCTION(&i);
+	LOG4VTM(INFO,_T("current thread: ") << GetCurrentThreadId());
+	const int times = 3000;
+	int count = 0;
+	do 
+	{
+		const int nInterval = get_random(0, 3000);
+		const int nLevel = nInterval % 6;
+		if(nLevel == 0) {
+			LOG4VTM(ERROR,_T("this is a ERROR log, times: ") << count);
+		} else if(nLevel == 1) {
+			LOG4VTM(FATAL, _T("this is a FATAL log, times: ") << count);
+		} else if(nLevel == 2) {
+			LOG4VTM(INFO,_T("this is a INFO log, times: ") << count);
+		} else if(nLevel == 3) {
+			LOG4VTM(DEBUG,_T("this is a DEBUG log, times: ") << count);
+		} else if(nLevel == 4) {
+			LOG4VTM(WARN,_T("this is a WRAN log, times: ") << count);
+		} else if(nLevel == 5) {
+			LOG4VTM(TRACE,_T("this is a TRACE log, times: ") << count);
+		}
+		//Sleep(nInterval);
+	} while (++count < times);
+
+	return 0;
+}
+
+void MultiThreadTest()
+{
+	srand((int)time(0));
+	int count = 30;
+	HANDLE handle[30];
+	for(int i=0; i<30; ++i)
+		handle[i] = (HANDLE)_beginthreadex(NULL, 0,thread1, (LPVOID)i, 0, NULL);
+	
+	WaitForMultipleObjects(30, handle, TRUE, INFINITE);
+}
+
+void logInitize_SupportDiffLogLevel_OFF()
+{
+	std::string err_msg;
+	cmb::log_init_config config;
+	config.dev_name =_T("PinPad");
+	config.log_type = CMB_LOG_TYPE_FILE;
+	config.log_level = CMB_LOG_LEVEL_OFF;
+	config.log_dir =_T("C:\\rvc\\dbg\\");
+
+	cmb::log4vendor::init(config, err_msg);
+	assert(err_msg.empty());
+
+	LOG4VTM(TRACE,_T("The TRACE type message would not record!"));
+	LOG4VTM(INFO,_T("The INFO type message would not record!"));
+	LOG4VTM(WARN,_T("The WARN type message would not record!"));
+	LOG4VTM(ERROR,_T("The ERROR type message would not record!"));
+	LOG4VTM(FATAL,_T("The FATAL type message would not record!"));
+}
+
+int _tmain(int argc, _TCHAR* argv[])
+{
+	std::string err_msg;
+	assert(cmb::log4vendor::instance() != NULL);
+	{
+		cmb::log_init_config config1;
+		config1.dev_name =_T("");
+		config1.log_type = CMB_LOG_TYPE_FILE;
+		config1.log_dir = _T("C:\\rvc\\dbg\\");
+
+		cmb::log4vendor::init(config1, err_msg);
+		LOG4VTM(INFO,_T("This message would not be record with illegal dev name!"));
+		assert(!err_msg.empty() &&_T(""));
+
+	}
+
+	{
+		cmb::log_init_config config2;
+		config2.dev_name =_T("PinPad");
+		config2.log_type = ~(CMB_LOG_TYPE_CONSOLE | CMB_LOG_TYPE_FILE | CMB_LOG_TYPE_SOCKET);
+		config2.log_dir =_T("C:\\rvc\\dbg\\");
+		cmb::log4vendor::init(config2, err_msg);
+		LOG4VTM(INFO,_T("This message would not be record with illegal log type!"));
+		assert(!err_msg.empty() &&_T(""));
+	}
+
+
+	{
+		cmb::log_init_config config;
+		config.dev_name =_T("PinPad");
+		config.log_type = CMB_LOG_TYPE_FILE;
+		config.log_dir =_T("");
+
+		cmb::log4vendor::init(config, err_msg);
+		LOG4VTM(INFO,_T("This message would not be record with illegal dir path !"));
+		assert(!err_msg.empty() &&_T(""));
+
+	}
+
+	/*test befor log initialize.*/
+	testVoid();
+	testInt();
+	testDWORD();
+
+
+	logInitize_FileRecord();
+
+	//logInitize_Console();
+
+	//logInitize_SupportDirPathWithoutSlash();
+
+	//logInitize_SupportDiffLogLevel_ERROR();
+
+	//logInitize_SupportDiffLogLevel_OFF();
+
+	testVoid();
+	testInt();
+	testDWORD();
+
+	MultiThreadTest();
+
+	return 0;
+}
+

+ 12 - 1
addin/cmake/BuildMakeSettings.cmake

@@ -21,4 +21,15 @@ macro(rvc_set_library_output_dir _dir)
 	set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${_dir})
 	set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${_dir})
 	set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${_dir})
-endmacro(rvc_set_library_output_dir)
+endmacro(rvc_set_library_output_dir)
+
+macro(rvc_target_add_definitions _target _def)
+get_target_property(EXISTED_PROPERTIES ${_target} COMPILE_DEFINITIONS)
+message(STATUS "EXISTED_PROPERTIES: ${EXISTED_PROPERTIES}")
+string(LENGTH ${EXISTED_PROPERTIES} var)
+if(${var})
+	set_target_properties(${MODULE_NAME} PROPERTIES COMPILE_DEFINITIONS "${EXISTED_PROPERTIES};${_def}")
+else()
+	set_target_properties(${MODULE_NAME} PROPERTIES COMPILE_DEFINITIONS "${_def}")
+endif()
+endmacro(rvc_target_add_definitions)

+ 3 - 1
addin/cmake/WindowsDLLVersion.cmake

@@ -17,7 +17,9 @@ macro(rvc_set_win_dll_ver _prefix _ver)
 	endif()
 	message(STATUS "${_prefix}_VERSION = ${${_prefix}_VERSION_FULL}")
 
+	if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/version.h.in)
 	configure_file(${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version.h)
+	endif()
 
 	# On windows create dll version information.
 	if (WIN32)
@@ -26,7 +28,7 @@ macro(rvc_set_win_dll_ver _prefix _ver)
 	  set (RC_VERSION_BUILD ${${_prefix}_VERSION_MINOR})
 	  set (RC_VERSION_PATCH ${${_prefix}_VERSION_REVISION})
 	  configure_file(
-		${CMAKE_SOURCE_DIR}/Version.rc.in
+		${CMAKE_SOURCE_DIR}/version.rc.in
 		${CMAKE_CURRENT_BINARY_DIR}/version.rc
 		@ONLY)