From cabaac4258326d3936c4445ea40a899cb932e64a Mon Sep 17 00:00:00 2001 From: Aregtech <49253642+aregtech@users.noreply.github.com> Date: Sun, 7 Jan 2024 21:42:16 +0100 Subject: [PATCH] 254 log observer console application (#293) * Added the log observer console application --- areg-sdk.sln | 15 + framework/CMakeLists.txt | 20 +- framework/areg-extend.vcxproj | 6 +- framework/areg-extend.vcxproj.filters | 6 +- framework/areg/base/GESwitches.h | 4 +- framework/areg/base/NEString.hpp | 50 +- framework/areg/base/TEArrayList.hpp | 6 +- framework/areg/component/NEService.hpp | 6 +- framework/areg/ipc/NERemoteService.hpp | 12 + .../areg/ipc/ServiceClientConnectionBase.hpp | 42 +- .../areg/ipc/ServiceEventConsumerBase.hpp | 6 + .../areg/ipc/private/ClientReceiveThread.cpp | 7 +- .../areg/ipc/private/ClientReceiveThread.hpp | 43 +- .../areg/ipc/private/ClientSendThread.cpp | 8 +- .../areg/ipc/private/ClientSendThread.hpp | 41 +- .../areg/ipc/private/NERemoteService.cpp | 2 + framework/areg/ipc/private/RouterClient.cpp | 45 +- .../private/ServiceClientConnectionBase.cpp | 90 ++- framework/areg/trace/NETrace.hpp | 28 +- framework/areg/trace/private/NETrace.cpp | 42 +- framework/areg/trace/private/NetTcpLogger.cpp | 44 +- framework/areg/trace/private/TraceManager.cpp | 9 +- framework/areg/trace/private/TraceManager.hpp | 15 +- .../extend/console/SystemServiceConsole.hpp | 52 +- .../console/private/SystemServiceConsole.cpp | 48 +- framework/extend/service/DataRateHelper.hpp | 158 +++++ .../service/ServiceCommunicatonBase.hpp | 90 ++- .../extend/service/SystemServiceBase.hpp | 50 +- .../extend/service/private/CMakeLists.txt | 1 + .../extend/service/private/DataRateHelper.cpp | 68 ++ framework/extend/service/private/Makefile | 1 + .../service/private/ServerReceiveThread.cpp | 9 +- .../{ => private}/ServerReceiveThread.hpp | 44 +- .../service/private/ServerSendThread.cpp | 9 +- .../{ => private}/ServerSendThread.hpp | 48 +- .../private/ServiceCommunicatonBase.cpp | 9 + .../service/private/SystemServiceBase.cpp | 17 +- framework/logger/app/private/Logger.cpp | 10 +- .../app/private/LoggerConsoleService.cpp | 2 +- .../private/LoggerMessageProcessor.cpp | 35 +- .../private/LoggerMessageProcessor.hpp | 25 +- .../service/private/LoggerServerService.cpp | 29 +- framework/logobserver.vcxproj | 62 ++ framework/logobserver.vcxproj.filters | 62 ++ .../mcrouter/app/private/MulticastRouter.cpp | 15 +- .../app/private/RouterConsoleService.cpp | 2 +- framework/observer/CMakeLists.txt | 1 + framework/observer/Makefile | 12 +- framework/observer/app/CMakeLists.txt | 5 + framework/observer/app/LogObserver.hpp | 298 ++++++++ framework/observer/app/Makefile | 26 + .../observer/app/NELogObserverSettings.hpp | 63 ++ framework/observer/app/private/CMakeLists.txt | 6 + .../observer/app/private/LogObserver.cpp | 670 ++++++++++++++++++ framework/observer/app/private/Makefile | 5 + .../app/private/NELogObserverSettings.cpp | 19 + .../app/private/posix/LogObserverPosix.cpp | 42 ++ .../app/private/win32/LogObserverWin32.cpp | 90 +++ framework/observer/app/resources/RCa05912 | Bin 0 -> 6604 bytes .../observer/app/resources/logobserver.ico | Bin 0 -> 23558 bytes .../observer/app/resources/logobserver.rc | Bin 0 -> 6574 bytes framework/observer/app/resources/resource.hpp | 9 + framework/observer/app/resources/small.ico | Bin 0 -> 23558 bytes .../observer/app/resources/targetver.hpp | 16 + framework/observer/lib/LogObserverApi.h | 149 +++- framework/observer/lib/LogObserverSwitches.h | 2 +- framework/observer/lib/Makefile | 15 +- .../observer/lib/private/LogObserverApi.cpp | 147 +++- .../observer/lib/private/LoggerClient.cpp | 205 +++++- .../observer/lib/private/LoggerClient.hpp | 63 +- .../lib/private/ObserverMessageProcessor.cpp | 240 ++++--- msvc_setup.props | 4 +- 72 files changed, 2915 insertions(+), 565 deletions(-) create mode 100644 framework/extend/service/DataRateHelper.hpp create mode 100644 framework/extend/service/private/DataRateHelper.cpp rename framework/extend/service/{ => private}/ServerReceiveThread.hpp (77%) rename framework/extend/service/{ => private}/ServerSendThread.hpp (79%) create mode 100644 framework/logobserver.vcxproj create mode 100644 framework/logobserver.vcxproj.filters create mode 100644 framework/observer/app/CMakeLists.txt create mode 100644 framework/observer/app/LogObserver.hpp create mode 100644 framework/observer/app/Makefile create mode 100644 framework/observer/app/NELogObserverSettings.hpp create mode 100644 framework/observer/app/private/CMakeLists.txt create mode 100644 framework/observer/app/private/LogObserver.cpp create mode 100644 framework/observer/app/private/Makefile create mode 100644 framework/observer/app/private/NELogObserverSettings.cpp create mode 100644 framework/observer/app/private/posix/LogObserverPosix.cpp create mode 100644 framework/observer/app/private/win32/LogObserverWin32.cpp create mode 100644 framework/observer/app/resources/RCa05912 create mode 100644 framework/observer/app/resources/logobserver.ico create mode 100644 framework/observer/app/resources/logobserver.rc create mode 100644 framework/observer/app/resources/resource.hpp create mode 100644 framework/observer/app/resources/small.ico create mode 100644 framework/observer/app/resources/targetver.hpp diff --git a/areg-sdk.sln b/areg-sdk.sln index 4bd071a59..c595e5ae3 100644 --- a/areg-sdk.sln +++ b/areg-sdk.sln @@ -650,6 +650,13 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "observerapi", "framework\observerapi.vcxproj", "{B29F438E-904C-4929-903C-F4673182A417}" ProjectSection(ProjectDependencies) = postProject {2DF8165C-EDE2-4F76-8D2C-2FFE82CB6CE5} = {2DF8165C-EDE2-4F76-8D2C-2FFE82CB6CE5} + {FBC5BEAE-01B9-4943-A5CB-0D3DE2067EB3} = {FBC5BEAE-01B9-4943-A5CB-0D3DE2067EB3} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "logobserver", "framework\logobserver.vcxproj", "{6941F2A7-F0C7-4293-8646-AF68A7E35183}" + ProjectSection(ProjectDependencies) = postProject + {2DF8165C-EDE2-4F76-8D2C-2FFE82CB6CE5} = {2DF8165C-EDE2-4F76-8D2C-2FFE82CB6CE5} + {B29F438E-904C-4929-903C-F4673182A417} = {B29F438E-904C-4929-903C-F4673182A417} EndProjectSection EndProject Global @@ -1196,6 +1203,14 @@ Global {B29F438E-904C-4929-903C-F4673182A417}.Release|Win32.Build.0 = Release|Win32 {B29F438E-904C-4929-903C-F4673182A417}.Release|x64.ActiveCfg = Release|x64 {B29F438E-904C-4929-903C-F4673182A417}.Release|x64.Build.0 = Release|x64 + {6941F2A7-F0C7-4293-8646-AF68A7E35183}.Debug|Win32.ActiveCfg = Debug|Win32 + {6941F2A7-F0C7-4293-8646-AF68A7E35183}.Debug|Win32.Build.0 = Debug|Win32 + {6941F2A7-F0C7-4293-8646-AF68A7E35183}.Debug|x64.ActiveCfg = Debug|x64 + {6941F2A7-F0C7-4293-8646-AF68A7E35183}.Debug|x64.Build.0 = Debug|x64 + {6941F2A7-F0C7-4293-8646-AF68A7E35183}.Release|Win32.ActiveCfg = Release|Win32 + {6941F2A7-F0C7-4293-8646-AF68A7E35183}.Release|Win32.Build.0 = Release|Win32 + {6941F2A7-F0C7-4293-8646-AF68A7E35183}.Release|x64.ActiveCfg = Release|x64 + {6941F2A7-F0C7-4293-8646-AF68A7E35183}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt index cf3e9e3de..0876b7477 100644 --- a/framework/CMakeLists.txt +++ b/framework/CMakeLists.txt @@ -43,12 +43,6 @@ set_target_properties(areg PROPERTIES CXX_STANDARD ${AREG_CXX_STANDARD} CXX_STAN # build areg extended static library addStaticLib(areg-extend "${extend_SRC}") -# build mcrouter executable -addExecutable(mcrouter "${mcrouter_SRC}") - -# build logger executable -addExecutable(logger "${logger_SRC}") - # build observer API library if (AREG_OBSERVER_LIB MATCHES "shared") # in case of Windows add DEF file. @@ -83,6 +77,20 @@ else(AREG_OBSERVER_LIB MATCHES "shared") endif(AREG_OBSERVER_LIB MATCHES "shared") +# build mcrouter executable +addExecutable(mcrouter "${mcrouter_SRC}") + +# build logger executable +addExecutable(logger "${logger_SRC}") + +# build log observer console application +addExecutableEx(logobserver "${logobserver_SRC}" observerapi) +if (AREG_OBSERVER_LIB MATCHES "shared") + target_compile_definitions(logobserver PRIVATE IMP_OBSERVER_DLL) +else(AREG_OBSERVER_LIB MATCHES "shared") + target_compile_definitions(observerapi PRIVATE IMP_OBSERVER_LIB) +endif(AREG_OBSERVER_LIB MATCHES "shared") + # copying log and router init files to 'bin/config' file(MAKE_DIRECTORY ${AREG_OUTPUT_BIN}/config) file(COPY ${AREG_BASE}/areg/resources/areg.init DESTINATION ${AREG_OUTPUT_BIN}/config) diff --git a/framework/areg-extend.vcxproj b/framework/areg-extend.vcxproj index 84c78523a..91e04df52 100644 --- a/framework/areg-extend.vcxproj +++ b/framework/areg-extend.vcxproj @@ -45,6 +45,7 @@ + @@ -61,13 +62,14 @@ + - - + + diff --git a/framework/areg-extend.vcxproj.filters b/framework/areg-extend.vcxproj.filters index c322734c6..88d28bf3d 100644 --- a/framework/areg-extend.vcxproj.filters +++ b/framework/areg-extend.vcxproj.filters @@ -14,6 +14,7 @@ + @@ -25,12 +26,13 @@ - - + + + diff --git a/framework/areg/base/GESwitches.h b/framework/areg/base/GESwitches.h index 84bf0d356..bbf7e009f 100644 --- a/framework/areg/base/GESwitches.h +++ b/framework/areg/base/GESwitches.h @@ -175,9 +175,11 @@ #endif // WIN32 // By default, no AREG extended features. -#ifndef AREG_EXTENDED +#if !defined(AREG_EXTENDED) && !defined(AREG_EXTEND) #pragma message("The AREG_EXTENDED is not defined, setting default value 0") #define AREG_EXTENDED 0 +#elif defined(AREG_EXTEND) && !defined(AREG_EXTENDED) + #define AREG_EXTENDED AREG_EXTEND #endif // AREG_EXTENDED // By default, compile with logs diff --git a/framework/areg/base/NEString.hpp b/framework/areg/base/NEString.hpp index fd367e050..973e73f2e 100644 --- a/framework/areg/base/NEString.hpp +++ b/framework/areg/base/NEString.hpp @@ -688,21 +688,27 @@ namespace NEString * \brief Returns true if a give string starts with specified phrase. * \param strString The string to check the phrase. * \param phrase The phrase to check. + * \param ch The character to check. * \param caseSensitive If false, it with check ignoring upper / lower case. Otherwise, checks exact match. * \return Returns true if the string starts with given phrase. **/ template bool stringStartsWith(const CharType * strString, const CharType * phrase, bool caseSensitive = true); + template + bool stringStartsWith(const CharType * strString, const CharType ch, bool caseSensitive = true); /** * \brief Returns true if a give string ends with specified phrase. * \param strString The string to check the phrase. * \param phrase The phrase to check. + * \param ch The character to check. * \param caseSensitive If false, it with check ignoring upper / lower case. Otherwise, checks exact match. * \return Returns true if the string ends with given phrase. **/ template bool stringEndsWith(const CharType * strString, const CharType * phrase, bool caseSensitive = true); + template + bool stringEndsWith(const CharType * strString, const CharType ch, bool caseSensitive = true); /** * \brief Returns printable string of given buffer. The buffer should be possible to modify. @@ -1252,7 +1258,7 @@ NEString::CharPos NEString::findFirst( const CharType * strPhrase template bool NEString::stringStartsWith(const CharType * strString, const CharType * phrase, bool caseSensitive /*= true*/) { - bool result = false; + bool result{ false }; if ((isEmpty(strString) == false) && (isEmpty(phrase) == false)) { result = true; @@ -1279,10 +1285,29 @@ bool NEString::stringStartsWith(const CharType * strString, const CharType * phr return result; } +template +bool NEString::stringStartsWith(const CharType* strString, const CharType ch, bool caseSensitive) +{ + bool result{ false }; + if (isEmpty(strString) == false) + { + if (caseSensitive) + { + result = *strString == ch; + } + else + { + result = NEString::makeAsciiLower(*strString) == NEString::makeAsciiLower(ch); + } + } + + return result; +} + template bool NEString::stringEndsWith(const CharType * strString, const CharType * phrase, bool caseSensitive /*= true*/) { - bool result = false; + bool result{ false }; if ((isEmpty(strString) == false) && (isEmpty(phrase) == false)) { int lenString = NEString::getStringLength(strString); @@ -1299,6 +1324,27 @@ bool NEString::stringEndsWith(const CharType * strString, const CharType * phras return result; } +template +bool NEString::stringEndsWith(const CharType* strString, const CharType ch, bool caseSensitive /*= true*/) +{ + bool result{ false }; + if (isEmpty(strString) == false) + { + int len = NEString::getStringLength(strString); + ASSERT(len != 0); + if (caseSensitive) + { + result = strString[len - 1] == ch; + } + else + { + result = NEString::makeAsciiLower(strString[len - 1]) == NEString::makeAsciiLower(ch); + } + } + + return result; +} + template NEString::CharCount NEString::removeChar(const CharType chRemove, CharType* strSource, NEString::CharCount count /*= NEString::COUNT_ALL*/, bool removeAll /*= true*/) { diff --git a/framework/areg/base/TEArrayList.hpp b/framework/areg/base/TEArrayList.hpp index 815564299..07abf9188 100644 --- a/framework/areg/base/TEArrayList.hpp +++ b/framework/areg/base/TEArrayList.hpp @@ -484,8 +484,12 @@ inline TEArrayList::TEArrayList( const std::vector & src ) template inline TEArrayList::TEArrayList(const VALUE* list, uint32_t count) : Constless>( ) - , mValueList( list, list != nullptr ? count : 0) + , mValueList( list != nullptr ? count : 0) { + for (uint32_t i = 0; i < count; ++i) + { + mValueList.at(i) = list[i]; + } } template diff --git a/framework/areg/component/NEService.hpp b/framework/areg/component/NEService.hpp index 6aeddbc73..e8b5fdec7 100644 --- a/framework/areg/component/NEService.hpp +++ b/framework/areg/component/NEService.hpp @@ -1056,6 +1056,8 @@ namespace NEService NEService::eInstanceBitness ciBitness { NEService::eInstanceBitness::BitnessUnknown }; //!< The cookie of the connected instance. ITEM_ID ciCookie { NEService::COOKIE_UNKNOWN }; + //!< The connection timestamp + TIME64 ciTimestamp { 0 }; //!< The name of the application String ciInstance { "" }; //!< The optional file location @@ -1311,7 +1313,7 @@ inline NEService::eDataStateType NEService::ProxyData::getParamState( unsigned i **/ inline IEOutStream& operator << (IEOutStream& stream, const NEService::sServiceConnectedInstance & output) { - stream << output.ciSource << output.ciBitness << output.ciCookie << output.ciInstance << output.ciLocation; + stream << output.ciSource << output.ciBitness << output.ciCookie << output.ciTimestamp << output.ciInstance << output.ciLocation; return stream; } @@ -1322,7 +1324,7 @@ inline IEOutStream& operator << (IEOutStream& stream, const NEService::sServiceC **/ inline const IEInStream& operator >> (const IEInStream& stream, NEService::sServiceConnectedInstance & input) { - stream >> input.ciSource >> input.ciBitness >> input.ciCookie >> input.ciInstance >> input.ciLocation; + stream >> input.ciSource >> input.ciBitness >> input.ciCookie >> input.ciTimestamp >> input.ciInstance >> input.ciLocation; return stream; } diff --git a/framework/areg/ipc/NERemoteService.hpp b/framework/areg/ipc/NERemoteService.hpp index 1fa41f407..a402421df 100644 --- a/framework/areg/ipc/NERemoteService.hpp +++ b/framework/areg/ipc/NERemoteService.hpp @@ -66,6 +66,17 @@ namespace NERemoteService , ServiceLogger = 2 //!< Message logging service. }; + /** + * \brief Indicates the connect or disconnect of the remote instance. + **/ + enum eRemoteConnection : uint32_t + { + /* Remote instance is disconnected. */ + RemoteDisconnected = 0 + /* Remote instance is connected. */ + , RemoteConnected = 1 + }; + /** * \brief NERemoteService::DEFAULT_REMOTE_SERVICE_ENABLED * Message router enable / disable default flag. If true, by default it is enabled. @@ -272,5 +283,6 @@ namespace NERemoteService ////////////////////////////////////////////////////////////////////////// IMPLEMENT_STREAMABLE(NERemoteService::eRemoteServices); IMPLEMENT_STREAMABLE(NERemoteService::eConnectionTypes); +IMPLEMENT_STREAMABLE(NERemoteService::eRemoteConnection); #endif // AREG_IPC_NEREMOTESERVICE_HPP diff --git a/framework/areg/ipc/ServiceClientConnectionBase.hpp b/framework/areg/ipc/ServiceClientConnectionBase.hpp index 06231afa6..e23bfc35c 100644 --- a/framework/areg/ipc/ServiceClientConnectionBase.hpp +++ b/framework/areg/ipc/ServiceClientConnectionBase.hpp @@ -25,7 +25,6 @@ #include "areg/ipc/ClientConnection.hpp" #include "areg/ipc/private/ClientReceiveThread.hpp" #include "areg/ipc/private/ClientSendThread.hpp" -#include "areg/ipc/NERemoteService.hpp" #include "areg/component/Channel.hpp" #include "areg/component/Timer.hpp" #include "areg/base/SynchObjects.hpp" @@ -119,6 +118,18 @@ class AREG_API ServiceClientConnectionBase : public IEServiceConnectionProvi **/ inline uint32_t queryBytesReceived( void ); + /** + * \brief Enable or disable the data rate calculation. + * \param enable If true, the data rate calculation is enabled. + * Otherwise, it is disabled. + **/ + inline void enableCalculateDataRate(bool enable); + + /** + * \brief Returns enable or disable the data rate calculation flag. + **/ + inline bool isCalculateDataRateEnabled(void) const; + /** * \brief Returns true if the connection status is either connecting or connected. **/ @@ -149,6 +160,18 @@ class AREG_API ServiceClientConnectionBase : public IEServiceConnectionProvi ////////////////////////////////////////////////////////////////////////// protected: +/************************************************************************/ +// ServiceClientConnectionBase interface overrides +/************************************************************************/ + + /** + * \brief Triggered when get service notifies the client the connection + * status like connection accepted, disconnected or rejected. + * Override the method if need custom connection reaction. + * \param msgReceived The message sent by service to the client. + **/ + virtual void serviceConnectionEvent(const RemoteMessage& msgReceived); + /************************************************************************/ // IEServiceConnectionProvider interface overrides /************************************************************************/ @@ -280,6 +303,12 @@ class AREG_API ServiceClientConnectionBase : public IEServiceConnectionProvi **/ virtual void onServiceMessageSend(const RemoteMessage& msgSend) override; + /** + * \brief Called when need to inform the channel connection. + * \param cookie The channel connection cookie. + **/ + virtual void onChannelConnected(const ITEM_ID & cookie) override; + ////////////////////////////////////////////////////////////////////////// // Protected operations and attributes ////////////////////////////////////////////////////////////////////////// @@ -459,6 +488,17 @@ inline uint32_t ServiceClientConnectionBase::queryBytesReceived( void ) return mThreadReceive.extractDataReceive(); } +inline void ServiceClientConnectionBase::enableCalculateDataRate(bool enable) +{ + mThreadReceive.setEnableCalculateData(enable); + mThreadSend.setEnableCalculateData(enable); +} + +inline bool ServiceClientConnectionBase::isCalculateDataRateEnabled(void) const +{ + return mThreadReceive.isCalculateDataEnabled() && mThreadSend.isCalculateDataEnabled(); +} + inline bool ServiceClientConnectionBase::isConnectState( void ) const { return (static_cast(mConnectionState) & static_cast(ServiceClientConnectionBase::eConnectionState::ConnectState)); diff --git a/framework/areg/ipc/ServiceEventConsumerBase.hpp b/framework/areg/ipc/ServiceEventConsumerBase.hpp index fb0e3fc84..1f9b6fa48 100644 --- a/framework/areg/ipc/ServiceEventConsumerBase.hpp +++ b/framework/areg/ipc/ServiceEventConsumerBase.hpp @@ -106,6 +106,12 @@ class AREG_API IEServiceEventConsumerBase **/ virtual void onServiceMessageSend(const RemoteMessage& msgSend) = 0; + /** + * \brief Called when need to inform the channel connection. + * \param cookie The channel connection cookie. + **/ + virtual void onChannelConnected(const ITEM_ID & cookie) = 0; + ////////////////////////////////////////////////////////////////////////// // Forbidden calls ////////////////////////////////////////////////////////////////////////// diff --git a/framework/areg/ipc/private/ClientReceiveThread.cpp b/framework/areg/ipc/private/ClientReceiveThread.cpp index 5d9e8c2db..da0932c3c 100644 --- a/framework/areg/ipc/private/ClientReceiveThread.cpp +++ b/framework/areg/ipc/private/ClientReceiveThread.cpp @@ -28,6 +28,7 @@ ClientReceiveThread::ClientReceiveThread(IERemoteMessageHandler& remoteService, , mRemoteService ( remoteService ) , mConnection ( connection ) , mBytesReceive ( 0 ) + , mSaveDataReceive ( false ) { } @@ -58,7 +59,11 @@ bool ClientReceiveThread::runDispatcher(void) } else { - mBytesReceive += static_cast(sizeReceive); + if (mSaveDataReceive) + { + mBytesReceive += static_cast(sizeReceive); + } + mRemoteService.processReceivedMessage( msgReceived, mConnection.getSocket( ) ); } diff --git a/framework/areg/ipc/private/ClientReceiveThread.hpp b/framework/areg/ipc/private/ClientReceiveThread.hpp index 1aba429a6..5d2f24f7e 100644 --- a/framework/areg/ipc/private/ClientReceiveThread.hpp +++ b/framework/areg/ipc/private/ClientReceiveThread.hpp @@ -21,6 +21,8 @@ #include "areg/base/GEGlobal.h" #include "areg/component/DispatcherThread.hpp" +#include + /************************************************************************ * Dependencies ************************************************************************/ @@ -63,7 +65,19 @@ class ClientReceiveThread : public DispatcherThread * \brief Returns accumulative value of received data size and rests the existing value to zero. * The operations are atomic. The value can be used to display data rate, for example. **/ - inline uint32_t extractDataReceive( void ); + inline uint32_t extractDataReceive( void ) const; + + /** + * \brief Call to enable or disable the received data calculation. + * It as well resets the existing calculated data. + * \param enable Flag, indicating whether data calculation is enabled or not. + **/ + inline void setEnableCalculateData(bool enable); + + /** + * \brief Returns flag, indicating whether data calculation is enabled or not. + **/ + inline bool isCalculateDataEnabled(void) const; protected: /************************************************************************/ @@ -86,16 +100,21 @@ class ClientReceiveThread : public DispatcherThread /** * \brief The instance of remote service handler to dispatch messages. **/ - IERemoteMessageHandler& mRemoteService; + IERemoteMessageHandler& mRemoteService; /** * \brief The instance of connection to receive messages from remote routing service. **/ - ClientConnection & mConnection; + ClientConnection & mConnection; /** * \brief Accumulative value of received data size. */ - std::atomic_uint mBytesReceive; + mutable std::atomic_uint mBytesReceive; + + /** + * \brief Flag, indicating whether data calculation is enabled or disabled. By default, it is disabled. + **/ + bool mSaveDataReceive; ////////////////////////////////////////////////////////////////////////// // Forbidden calls @@ -105,9 +124,23 @@ class ClientReceiveThread : public DispatcherThread DECLARE_NOCOPY_NOMOVE( ClientReceiveThread ); }; -inline uint32_t ClientReceiveThread::extractDataReceive( void ) +inline uint32_t ClientReceiveThread::extractDataReceive( void ) const { return static_cast(mBytesReceive.exchange(0)); } +inline void ClientReceiveThread::setEnableCalculateData(bool enable) +{ + if (mSaveDataReceive != enable) + { + mBytesReceive.store(0u); + mSaveDataReceive = enable; + } +} + +inline bool ClientReceiveThread::isCalculateDataEnabled(void) const +{ + return mSaveDataReceive; +} + #endif // AREG_IPC_PRIVATE_CLIENTRECEIVETHREAD_HPP diff --git a/framework/areg/ipc/private/ClientSendThread.cpp b/framework/areg/ipc/private/ClientSendThread.cpp index e3116f77c..b4dafd4a5 100644 --- a/framework/areg/ipc/private/ClientSendThread.cpp +++ b/framework/areg/ipc/private/ClientSendThread.cpp @@ -25,9 +25,12 @@ DEF_TRACE_SCOPE(areg_ipc_private_ClientSendThread_readyForEvents); ClientSendThread::ClientSendThread(IERemoteMessageHandler& remoteService, ClientConnection & connection, const String& namePrefix ) : DispatcherThread ( namePrefix + NEConnection::CLIENT_SEND_MESSAGE_THREAD ) + , IESendMessageEventConsumer( ) + , mRemoteService ( remoteService ) , mConnection ( connection ) , mBytesSend ( 0 ) + , mSaveDataSend ( false ) { } @@ -58,7 +61,10 @@ void ClientSendThread::processEvent( const SendMessageEventData & data ) int sizeSend = mConnection.sendMessage( msg ); if ( sizeSend > 0 ) { - mBytesSend += static_cast(sizeSend); + if (mSaveDataSend) + { + mBytesSend += static_cast(sizeSend); + } } else { diff --git a/framework/areg/ipc/private/ClientSendThread.hpp b/framework/areg/ipc/private/ClientSendThread.hpp index af9424887..dbf4aad61 100644 --- a/framework/areg/ipc/private/ClientSendThread.hpp +++ b/framework/areg/ipc/private/ClientSendThread.hpp @@ -65,7 +65,19 @@ class ClientSendThread : public DispatcherThread * \brief Returns accumulative value of sent data size and rests the existing value to zero. * The operations are atomic. The value can be used to display data rate, for example. **/ - inline uint32_t extractDataSend( void ); + inline uint32_t extractDataSend( void ) const; + + /** + * \brief Call to enable or disable the received data calculation. + * It as well resets the existing calculated data. + * \param enable Flag, indicating whether data calculation is enabled or not. + **/ + inline void setEnableCalculateData(bool enable); + + /** + * \brief Returns flag, indicating whether data calculation is enabled or not. + **/ + inline bool isCalculateDataEnabled(void) const; protected: /************************************************************************/ @@ -114,16 +126,21 @@ class ClientSendThread : public DispatcherThread /** * \brief The instance of remote service handler to dispatch messages. **/ - IERemoteMessageHandler& mRemoteService; + IERemoteMessageHandler& mRemoteService; /** * \brief The instance of connection to send messages from remote routing service. **/ - ClientConnection & mConnection; + ClientConnection & mConnection; /** * \brief Accumulative value of sent data size. **/ - std::atomic_uint mBytesSend; + mutable std::atomic_uint mBytesSend; + + /** + * \brief Flag, indicating whether data calculation is enabled or disabled. By default, it is disabled. + **/ + bool mSaveDataSend; ////////////////////////////////////////////////////////////////////////// // Forbidden calls @@ -133,9 +150,23 @@ class ClientSendThread : public DispatcherThread DECLARE_NOCOPY_NOMOVE( ClientSendThread ); }; -inline uint32_t ClientSendThread::extractDataSend( void ) +inline uint32_t ClientSendThread::extractDataSend( void ) const { return static_cast(mBytesSend.exchange( 0 )); } +inline void ClientSendThread::setEnableCalculateData(bool enable) +{ + if (mSaveDataSend != enable) + { + mBytesSend.store(0u); + mSaveDataSend = enable; + } +} + +inline bool ClientSendThread::isCalculateDataEnabled(void) const +{ + return mSaveDataSend; +} + #endif // AREG_IPC_PRIVATE_CLIENTSENDTHREAD_HPP diff --git a/framework/areg/ipc/private/NERemoteService.cpp b/framework/areg/ipc/private/NERemoteService.cpp index ce70b8b16..7141e698e 100644 --- a/framework/areg/ipc/private/NERemoteService.cpp +++ b/framework/areg/ipc/private/NERemoteService.cpp @@ -14,6 +14,7 @@ ************************************************************************/ #include "areg/ipc/NERemoteService.hpp" +#include "areg/base/DateTime.hpp" #include "areg/base/Process.hpp" #include "areg/base/RemoteMessage.hpp" #include "areg/component/NEService.hpp" @@ -446,6 +447,7 @@ AREG_API_IMPL RemoteMessage NERemoteService::createConnectRequest(const ITEM_ID instance.ciSource = msgSource; instance.ciBitness = static_cast(Process::getInstance().getBitness()); instance.ciCookie = source; + instance.ciTimestamp= static_cast(DateTime::getNow()); instance.ciInstance = Process::getInstance().getAppName(); instance.ciLocation = Process::getInstance().getPath(); diff --git a/framework/areg/ipc/private/RouterClient.cpp b/framework/areg/ipc/private/RouterClient.cpp index 77adbb5bc..039349999 100644 --- a/framework/areg/ipc/private/RouterClient.cpp +++ b/framework/areg/ipc/private/RouterClient.cpp @@ -18,14 +18,12 @@ #include "areg/ipc/private/NEConnection.hpp" #include "areg/component/RemoteEventFactory.hpp" -#include "areg/component/DispatcherThread.hpp" #include "areg/component/StreamableEvent.hpp" #include "areg/component/ResponseEvents.hpp" #include "areg/component/RequestEvents.hpp" #include "areg/component/NEService.hpp" #include "areg/appbase/Application.hpp" #include "areg/base/Process.hpp" -#include "areg/base/File.hpp" #include "areg/trace/GETrace.h" DEF_TRACE_SCOPE(areg_ipc_private_RouterClient_failedSendMessage); @@ -282,48 +280,7 @@ void RouterClient::processReceivedMessage( const RemoteMessage & msgReceived, So switch ( msgId ) { case NEService::eFuncIdRange::SystemServiceNotifyConnection: - { - NEService::eServiceConnection connection = NEService::eServiceConnection::ServiceConnectionUnknown; - ITEM_ID cookie = NEService::COOKIE_UNKNOWN; - msgReceived >> cookie; - msgReceived >> connection; - TRACE_DBG("Router connection notification. Connection status [ %s ], cookie [ %llu ]", NEService::getString(connection), cookie); - - switch ( connection ) - { - case NEService::eServiceConnection::ServiceConnected: - case NEService::eServiceConnection::ServicePending: - { - if ( msgReceived.getResult( ) == NEMemory::MESSAGE_SUCCESS ) - { - Lock lock( mLock ); - ASSERT( cookie == msgReceived.getTarget( ) ); - mClientConnection.setCookie( cookie ); - sendCommand( ServiceEventData::eServiceEventCommands::CMD_ServiceStarted ); - } - else - { - cancelConnection( ); - sendCommand( ServiceEventData::eServiceEventCommands::CMD_ServiceLost ); - } - } - break; - - case NEService::eServiceConnection::ServiceConnectionLost: - { - cancelConnection( ); - sendCommand( ServiceEventData::eServiceEventCommands::CMD_ServiceLost ); - } - break; - - default: - { - cancelConnection( ); - sendCommand( ServiceEventData::eServiceEventCommands::CMD_ServiceStopped ); - } - break; - } - } + serviceConnectionEvent(msgReceived); break; case NEService::eFuncIdRange::SystemServiceNotifyRegister: diff --git a/framework/areg/ipc/private/ServiceClientConnectionBase.cpp b/framework/areg/ipc/private/ServiceClientConnectionBase.cpp index 0178af424..a8173abd0 100644 --- a/framework/areg/ipc/private/ServiceClientConnectionBase.cpp +++ b/framework/areg/ipc/private/ServiceClientConnectionBase.cpp @@ -14,21 +14,12 @@ ************************************************************************/ #include "areg/ipc/ServiceClientConnectionBase.hpp" -#include "areg/component/DispatcherThread.hpp" - +#include "areg/component/NEService.hpp" +#include "areg/appbase/Application.hpp" #include "areg/ipc/IEServiceConnectionConsumer.hpp" #include "areg/ipc/ConnectionConfiguration.hpp" #include "areg/ipc/NERemoteService.hpp" #include "areg/ipc/private/NEConnection.hpp" - -#include "areg/component/DispatcherThread.hpp" -#include "areg/component/StreamableEvent.hpp" -#include "areg/component/ResponseEvents.hpp" -#include "areg/component/RequestEvents.hpp" -#include "areg/component/NEService.hpp" -#include "areg/appbase/Application.hpp" -#include "areg/base/Process.hpp" -#include "areg/base/File.hpp" #include "areg/trace/GETrace.h" DEF_TRACE_SCOPE(areg_ipc_private_ServiceClientConnectionBase_onServiceReconnectTimerExpired); @@ -37,7 +28,9 @@ DEF_TRACE_SCOPE(areg_ipc_private_ServiceClientConnectionBase_onServiceConnection DEF_TRACE_SCOPE(areg_ipc_private_ServiceClientConnectionBase_onServiceConnectionStarted); DEF_TRACE_SCOPE(areg_ipc_private_ServiceClientConnectionBase_onServiceConnectionStopped); DEF_TRACE_SCOPE(areg_ipc_private_ServiceClientConnectionBase_onServiceConnectionLost); +DEF_TRACE_SCOPE(areg_ipc_private_ServiceClientConnectionBase_onChannelConnected); +DEF_TRACE_SCOPE(areg_ipc_private_ServiceClientConnectionBase_serviceConnectionEvent); DEF_TRACE_SCOPE(areg_ipc_private_ServiceClientConnectionBase_startConnection); DEF_TRACE_SCOPE(areg_ipc_private_ServiceClientConnectionBase_cancelConnection); @@ -76,6 +69,60 @@ ServiceClientConnectionBase::ServiceClientConnectionBase( const ITEM_ID & target ASSERT((target > NEService::TARGET_LOCAL) && (target < NEService::COOKIE_REMOTE_SERVICE)); } +void ServiceClientConnectionBase::serviceConnectionEvent(const RemoteMessage& msgReceived) +{ + TRACE_SCOPE(areg_ipc_private_ServiceClientConnectionBase_serviceConnectionEvent); + Lock lock(mLock); + + ITEM_ID cookie{ NEService::COOKIE_UNKNOWN }; + NEService::eServiceConnection connection{ NEService::eServiceConnection::ServiceConnectionUnknown }; + msgReceived >> cookie; + msgReceived >> connection; + TRACE_DBG("Remote service connection notification: status [ %s ], cookie [ %llu ]", NEService::getString(connection), cookie); + + switch (connection) + { + case NEService::eServiceConnection::ServiceConnected: + case NEService::eServiceConnection::ServicePending: + { + if (msgReceived.getResult() == NEMemory::MESSAGE_SUCCESS) + { + Lock lock(mLock); + ASSERT(cookie == msgReceived.getTarget()); + mClientConnection.setCookie(cookie); + onChannelConnected(cookie); + sendCommand(ServiceEventData::eServiceEventCommands::CMD_ServiceStarted); + } + else + { + cancelConnection(); + onChannelConnected(NEService::COOKIE_UNKNOWN); + sendCommand(ServiceEventData::eServiceEventCommands::CMD_ServiceLost); + } + } + break; + + case NEService::eServiceConnection::ServiceConnectionLost: + { + cancelConnection(); + onChannelConnected(NEService::COOKIE_UNKNOWN); + sendCommand(ServiceEventData::eServiceEventCommands::CMD_ServiceLost); + } + break; + + case NEService::eServiceConnection::ServiceRejected: + case NEService::eServiceConnection::ServiceFailed: + case NEService::eServiceConnection::ServiceShutdown: + default: + { + cancelConnection(); + onChannelConnected(NEService::COOKIE_UNKNOWN); + sendCommand(ServiceEventData::eServiceEventCommands::CMD_ServiceStopped); + } + break; + } +} + bool ServiceClientConnectionBase::setupServiceConnectionData(NERemoteService::eRemoteServices service, uint32_t connectTypes) { Lock lock( mLock ); @@ -303,6 +350,27 @@ void ServiceClientConnectionBase::onServiceMessageSend( const RemoteMessage & ms { } +void ServiceClientConnectionBase::onChannelConnected(const ITEM_ID& cookie) +{ + TRACE_SCOPE(areg_ipc_private_ServiceClientConnectionBase_onChannelConnected); + if (cookie >= NEService::COOKIE_REMOTE_SERVICE) + { + mChannel.setCookie(cookie); + mChannel.setSource(mMessageDispatcher.getId()); + mChannel.setTarget(mTarget); + + TRACE_DBG("Connected remote channel [ source = %llu, target = %llu, cookie = %llu ]", mChannel.getSource(), mChannel.getTarget(), mChannel.getCookie()); + } + else + { + TRACE_INFO("Disconnecting remote channel [ source = %llu, target = %llu, cookie = %llu ]", mChannel.getSource(), mChannel.getTarget(), mChannel.getCookie()); + + mChannel.setCookie(cookie); + mChannel.setSource(NEService::SOURCE_UNKNOWN); + mChannel.setTarget(NEService::TARGET_UNKNOWN); + } +} + bool ServiceClientConnectionBase::startConnection(void) { TRACE_SCOPE(areg_ipc_private_ServiceClientConnectionBase_startConnection); diff --git a/framework/areg/trace/NETrace.hpp b/framework/areg/trace/NETrace.hpp index b250b207b..761ba4987 100644 --- a/framework/areg/trace/NETrace.hpp +++ b/framework/areg/trace/NETrace.hpp @@ -20,8 +20,6 @@ #include "areg/base/GEGlobal.h" #include "areg/base/IEIOStream.hpp" -#include "areg/base/NECommon.hpp" -#include "areg/base/NESocket.hpp" #include "areg/base/RemoteMessage.hpp" #include "areg/base/String.hpp" #include "areg/base/TEArrayList.hpp" @@ -34,7 +32,6 @@ * Dependencies ************************************************************************/ class TraceScope; -class FileBase; ////////////////////////////////////////////////////////////////////////// // NETrace namespace declaration @@ -77,9 +74,9 @@ namespace NETrace **/ inline sScopeInfo(const char* name, uint32_t id, uint32_t prio); - String scopeName; //!< The name of the scope or scope group. - unsigned int scopeId; //!< The scope ID, can be 0 (NETrace::TRACE_SCOPE_ID_NONE). For scope group should be 0. - unsigned int scopePrio; //!< The scope priority. + String scopeName; //!< The name of the scope or scope group. + uint32_t scopeId; //!< The scope ID, can be 0 (NETrace::TRACE_SCOPE_ID_NONE). For scope group should be 0. + uint32_t scopePrio; //!< The scope priority. }; //!< The list of scope update structure. @@ -423,6 +420,17 @@ namespace NETrace **/ AREG_API unsigned int makeScopeId( const char * scopeName ); + /** + * \brief Returns the ID of given scope name. + * If the scope name is nullptr, empty or ends with grouping symbol '*', it returns 0. + * Otherwise, returns scope ID calculated by makeScopeId() method. + * \param scopeName The name of scope. If nullptr, empty or ends with grouping symbol '*', + * the return value is zero. + * \return Returns the ID of given scope name or returns zero if scope name is empty or + * ends with grouping symbol '*' + **/ + AREG_API unsigned int makeScopeIdEx(const char* scopeName); + /** * \brief Call to change the scope log priority. * \param scopeName The name of the existing scope. Ignored if scope does not exit. @@ -455,11 +463,17 @@ namespace NETrace AREG_API void logMessage(const RemoteMessage& message); /** - * \brief Log generated custom message locally bypassing priority settings of a scope. + * \brief Log local custom message ignoring process and thread names. * \param logMessage The structure that contains information to log a message. **/ AREG_API void logAnyMessageLocal(const NETrace::sLogMessage& logMessage); + /** + * \brief Log custom message considering process and thread names. + * \param logMessage The structure that contains information to log a message. + **/ + AREG_API void logAnyMessage(const NETrace::sLogMessage& logMessage); + /** * \brief Creates a message for logging service to register scopes with message priority. * \param source The ID of the source that generated the message. diff --git a/framework/areg/trace/private/NETrace.cpp b/framework/areg/trace/private/NETrace.cpp index a339bea91..dd3166375 100644 --- a/framework/areg/trace/private/NETrace.cpp +++ b/framework/areg/trace/private/NETrace.cpp @@ -24,7 +24,6 @@ #include "areg/component/NEService.hpp" #include "areg/trace/TraceScope.hpp" #include "areg/trace/private/TraceManager.hpp" -#include "areg/ipc/private/NEConnection.hpp" #include @@ -264,7 +263,16 @@ AREG_API_IMPL bool NETrace::saveLogging( const char * configFile ) AREG_API_IMPL unsigned int NETrace::makeScopeId( const char * scopeName ) { #if AREG_LOGS - return NEMath::crc32Calculate( scopeName ); + return NEMath::crc32Calculate(scopeName); +#else // !AREG_LOGS + return 0; +#endif // AREG_LOGS +} + +AREG_API_IMPL unsigned int NETrace::makeScopeIdEx(const char* scopeName) +{ +#if AREG_LOGS + return (NEString::stringEndsWith(scopeName, NELogging::SYNTAX_SCOPE_GROUP, true) ? NEMath::CHECKSUM_IGNORE : NETrace::makeScopeId(scopeName)); #else // !AREG_LOGS return 0; #endif // AREG_LOGS @@ -330,31 +338,22 @@ AREG_API_IMPL RemoteMessage NETrace::messageRegisterScopes(const ITEM_ID & sourc msgScope.setTarget(target != NEService::COOKIE_UNKNOWN ? target : NEService::COOKIE_LOGGER); msgScope.setSource(source != NEService::COOKIE_UNKNOWN ? source : NETrace::getCookie()); - unsigned int numPos = msgScope.getPosition(); - unsigned int count{ 0 }; - msgScope << count; // reserve space - - SCOPEPOS end = scopeList.invalidPosition(); - for (SCOPEPOS pos = scopeList.firstPosition(); pos != end; ++ count, pos = scopeList.nextPosition(pos)) + msgScope << static_cast(scopeList.getSize()); + const auto& list{ scopeList.getData() }; + for (const auto& entry : list) { - TraceScopePair tracePair; - scopeList.getAtPosition(pos, tracePair); - ASSERT(tracePair.second != nullptr); - msgScope << (*tracePair.second); + const TraceScope* scope = entry.second; + ASSERT(scope != nullptr); + msgScope << *scope; } - - // Write number of scopes - msgScope.setPosition(static_cast(numPos), IECursorPosition::eCursorPosition::PositionBegin); - msgScope << count; - msgScope.moveToEnd(); } return msgScope; } -AREG_API void NETrace::logAnyMessageLocal(const NETrace::sLogMessage& logMessage) +AREG_API_IMPL void NETrace::logAnyMessageLocal(const NETrace::sLogMessage& logMessage) { - return TraceManager::logMessage(logMessage); + TraceManager::logMessage(logMessage); } AREG_API_IMPL RemoteMessage NETrace::messageUpdateScopes(const ITEM_ID& source, const ITEM_ID& target, const NETrace::ScopeNames& scopeNames) @@ -378,6 +377,11 @@ AREG_API_IMPL RemoteMessage NETrace::messageUpdateScopes(const ITEM_ID& source, return msgScope; } +AREG_API_IMPL void NETrace::logAnyMessage(const NETrace::sLogMessage& logMessage) +{ + TraceManager::logMessage(SharedBuffer(reinterpret_cast(&logMessage), sizeof(NETrace::sLogMessage))); +} + AREG_API_IMPL RemoteMessage NETrace::messageUpdateScope(const ITEM_ID& source, const ITEM_ID& target, const String& scopeName, unsigned int scopeId, unsigned int scopePrio) { RemoteMessage msgScope; diff --git a/framework/areg/trace/private/NetTcpLogger.cpp b/framework/areg/trace/private/NetTcpLogger.cpp index 695c81381..fdcffd1f9 100644 --- a/framework/areg/trace/private/NetTcpLogger.cpp +++ b/framework/areg/trace/private/NetTcpLogger.cpp @@ -166,48 +166,8 @@ void NetTcpLogger::processReceivedMessage(const RemoteMessage & msgReceived, Soc switch (msgId) { case NEService::eFuncIdRange::SystemServiceNotifyConnection: - { - ITEM_ID cookie{ NEService::COOKIE_UNKNOWN }; - NEService::eServiceConnection connection{ NEService::eServiceConnection::ServiceConnectionUnknown }; - msgReceived >> cookie; - msgReceived >> connection; - - switch (connection) - { - case NEService::eServiceConnection::ServiceConnected: - case NEService::eServiceConnection::ServicePending: - { - if (msgReceived.getResult() == NEMemory::MESSAGE_SUCCESS) - { - Lock lock(mLock); - ASSERT(cookie == msgReceived.getTarget()); - mClientConnection.setCookie(cookie); - sendCommand(ServiceEventData::eServiceEventCommands::CMD_ServiceStarted); - } - else - { - cancelConnection(); - sendCommand(ServiceEventData::eServiceEventCommands::CMD_ServiceLost); - } - } - break; - - case NEService::eServiceConnection::ServiceRejected: - { - cancelConnection(); - sendCommand(ServiceEventData::eServiceEventCommands::CMD_ServiceStopped); - } - break; - - default: - { - cancelConnection(); - sendCommand(ServiceEventData::eServiceEventCommands::CMD_ServiceLost); - } - break; - } - } - break; + serviceConnectionEvent(msgReceived); + break; case NEService::eFuncIdRange::ServiceLogUpdateScopes: { diff --git a/framework/areg/trace/private/TraceManager.cpp b/framework/areg/trace/private/TraceManager.cpp index 5a26ea7b2..f12db750e 100644 --- a/framework/areg/trace/private/TraceManager.cpp +++ b/framework/areg/trace/private/TraceManager.cpp @@ -16,15 +16,11 @@ #include "areg/trace/private/TraceManager.hpp" #include "areg/appbase/Application.hpp" -#include "areg/base/Containers.hpp" #include "areg/base/File.hpp" -#include "areg/base/FileBuffer.hpp" -#include "areg/base/NEString.hpp" #include "areg/base/Process.hpp" #include "areg/trace/TraceScope.hpp" #include "areg/trace/private/LogMessage.hpp" -#include "areg/trace/private/TraceEvent.hpp" ////////////////////////////////////////////////////////////////////////// // TraceManager::TraceScopeMap class implementation @@ -53,6 +49,11 @@ void TraceManager::logMessage(const NETrace::sLogMessage& logData ) TraceManager::getInstance().sendLogEvent( TraceEventData(TraceEventData::eTraceAction::TraceLogMessage, logData) ); } +void TraceManager::logMessage(const SharedBuffer& logData) +{ + TraceManager::getInstance().sendLogEvent(TraceEventData(TraceEventData::eTraceAction::TraceLogMessage, logData)); +} + void TraceManager::logMessage(const RemoteMessage& logData) { TraceManager::getInstance().sendLogEvent( TraceEventData(TraceEventData::eTraceAction::TraceLogMessage, logData) ); diff --git a/framework/areg/trace/private/TraceManager.hpp b/framework/areg/trace/private/TraceManager.hpp index 804f4e612..b230da936 100644 --- a/framework/areg/trace/private/TraceManager.hpp +++ b/framework/areg/trace/private/TraceManager.hpp @@ -22,13 +22,8 @@ #include "areg/component/DispatcherThread.hpp" #include "areg/trace/private/TraceEvent.hpp" -#include "areg/base/Containers.hpp" -#include "areg/base/Version.hpp" #include "areg/base/String.hpp" #include "areg/base/SynchObjects.hpp" - -#include "areg/component/Timer.hpp" - #include "areg/trace/NETrace.hpp" #include "areg/trace/private/ScopeController.hpp" #include "areg/trace/private/FileLogger.hpp" @@ -89,8 +84,14 @@ class TraceManager : public DispatcherThread static void logMessage( const NETrace::sLogMessage & logData ); /** - * \brief Triggers and event log remote message. - * \param logDaya The instance of remote message buffer, which contains the + * \brief Triggers an event to log message contained in the shared buffer. + * \param logData The instance of message in shared buffer to og. + **/ + static void logMessage(const SharedBuffer& logData); + + /** + * \brief Triggers an event to log remote message. + * \param logData The instance of remote message buffer, which contains the * log message from another process. **/ static void logMessage( const RemoteMessage& logData ); diff --git a/framework/extend/console/SystemServiceConsole.hpp b/framework/extend/console/SystemServiceConsole.hpp index 532be0f93..b492e3843 100644 --- a/framework/extend/console/SystemServiceConsole.hpp +++ b/framework/extend/console/SystemServiceConsole.hpp @@ -23,13 +23,12 @@ #include "areg/component/IETimerConsumer.hpp" #include "areg/component/StubBase.hpp" -#include "areg/base/NECommon.hpp" #include "areg/component/Timer.hpp" /************************************************************************ * Dependencies ************************************************************************/ -class SystemServiceBase; +class DataRateHelper; ////////////////////////////////////////////////////////////////////////// // SystemServiceConsole class declaration @@ -43,43 +42,6 @@ class SystemServiceConsole : public Component , protected StubBase , protected IETimerConsumer { -////////////////////////////////////////////////////////////////////////// -// Internal types and constants. -////////////////////////////////////////////////////////////////////////// -public: - - //!< Bytes in 1 Kilobyte. - static constexpr uint32_t ONE_KILOBYTE { NECommon::ONE_KILOBYTE }; - //!< Bytes in 1 megabyte. - static constexpr uint32_t ONE_MEGABYTE { NECommon::ONE_MEGABYTE }; - //!< String kilobytes per second - static constexpr std::string_view MSG_KILOBYTES { "KBytes / sec." }; - //!< String megabytes per second - static constexpr std::string_view MSG_MEGABYTES { "MBytes / sec." }; - //!< String bytes per second - static constexpr std::string_view MSG_BYTES { " Bytes / sec." }; - -////////////////////////////////////////////////////////////////////////// -// DataRate helper class declaration. -////////////////////////////////////////////////////////////////////////// - /** - * \brief The helper class to calculate data rate and output message in MB, KB and Bytes. - **/ - class DataRate - { - ////////////////////////////////////////////////////////////////////////// - // Members. - ////////////////////////////////////////////////////////////////////////// - public: - /** - * \brief Calculates and initializes the data rate. - **/ - DataRate(uint32_t sizeBytes = 0); - - //!< This pair contains size in bytes and message indicating MB, KB or Bytes. - std::pair mRate; - }; - ////////////////////////////////////////////////////////////////////////// // Constructor / destructor ////////////////////////////////////////////////////////////////////////// @@ -87,18 +49,22 @@ class SystemServiceConsole : public Component /** * \brief Instantiates the component object. - * \param sysService The instance of the system service object. + * \param dataRate The pointer to the optional data rate helper object to extrate send and receive data rates. * \param entry The component entry object set in the model. * \param owner The instance of component owner thread. * \param data The optional component data set in system. Can be empty / no data. **/ - SystemServiceConsole( SystemServiceBase & sysService, const NERegistry::ComponentEntry & entry, ComponentThread & owner, NEMemory::uAlign OPT data ); + SystemServiceConsole(DataRateHelper* dataRate, const NERegistry::ComponentEntry & entry, ComponentThread & owner, NEMemory::uAlign OPT data ); /** * \brief Destructor. **/ virtual ~SystemServiceConsole( void ) = default; +////////////////////////////////////////////////////////////////////////// +// Overrides +////////////////////////////////////////////////////////////////////////// +protected: /************************************************************************/ // StubBase overrides. Triggered by Component on startup. /************************************************************************/ @@ -204,8 +170,8 @@ class SystemServiceConsole : public Component // Hidden member variables ////////////////////////////////////////////////////////////////////////// private: - SystemServiceBase & mSystemService; //!< The instance of system service object. - Timer mTimer; //!< The timer to run in component thread. + DataRateHelper* mDataRateHelper;//!< The pointer to utility object to retrieve data rate info. + Timer mTimer; //!< The timer to run in component thread. ////////////////////////////////////////////////////////////////////////// // Forbidden calls diff --git a/framework/extend/console/private/SystemServiceConsole.cpp b/framework/extend/console/private/SystemServiceConsole.cpp index 4ba7bc469..3724a75e4 100644 --- a/framework/extend/console/private/SystemServiceConsole.cpp +++ b/framework/extend/console/private/SystemServiceConsole.cpp @@ -18,46 +18,20 @@ ************************************************************************/ #include "extend/console/SystemServiceConsole.hpp" -#include "areg/appbase/Application.hpp" #include "areg/component/ComponentThread.hpp" #include "extend/console/Console.hpp" +#include "extend/service/DataRateHelper.hpp" #include "extend/service/NESystemService.hpp" -#include "extend/service/SystemServiceBase.hpp" - - ////////////////////////////////////////////////////////////////////////// - // SystemServiceConsole::DataRate helper class implementation - ////////////////////////////////////////////////////////////////////////// -SystemServiceConsole::DataRate::DataRate(uint32_t sizeBytes) - : mRate ( ) -{ - if (sizeBytes >= ONE_MEGABYTE) - { - double rate = static_cast(sizeBytes) / ONE_MEGABYTE; - mRate.first = static_cast(rate); - mRate.second= SystemServiceConsole::MSG_MEGABYTES; - } - else if (sizeBytes >= ONE_KILOBYTE) - { - double rate = static_cast(sizeBytes) / ONE_KILOBYTE; - mRate.first = static_cast(rate); - mRate.second= SystemServiceConsole::MSG_KILOBYTES; - } - else - { - mRate.first = static_cast(sizeBytes); - mRate.second = SystemServiceConsole::MSG_BYTES; - } -} ////////////////////////////////////////////////////////////////////////// // SystemServiceConsole class implementation ////////////////////////////////////////////////////////////////////////// -SystemServiceConsole::SystemServiceConsole( SystemServiceBase & sysService, const NERegistry::ComponentEntry & entry, ComponentThread & owner, NEMemory::uAlign OPT data ) +SystemServiceConsole::SystemServiceConsole(DataRateHelper* dataRate, const NERegistry::ComponentEntry & entry, ComponentThread & owner, NEMemory::uAlign OPT data ) : Component ( entry, owner ) , StubBase ( self( ), NEService::getEmptyInterface( ) ) , IETimerConsumer ( ) - , mSystemService ( sysService ) + , mDataRateHelper ( dataRate ) , mTimer ( self( ), "ConsoleServiceTimer" ) { } @@ -69,11 +43,11 @@ void SystemServiceConsole::startupServiceInterface( Component & holder ) Console & console = Console::getInstance( ); console.lockConsole( ); - if ( mSystemService.isVerbose( ) ) + if ( (mDataRateHelper != nullptr) && mDataRateHelper->isVerbose()) { - console.outputMsg( NESystemService::COORD_SEND_RATE, NESystemService::FORMAT_SEND_DATA.data( ), 0.0f, SystemServiceConsole::MSG_BYTES.data( ) ); - console.outputMsg( NESystemService::COORD_RECV_RATE, NESystemService::FORMAT_RECV_DATA.data( ), 0.0f, SystemServiceConsole::MSG_BYTES.data( ) ); + console.outputMsg( NESystemService::COORD_SEND_RATE, NESystemService::FORMAT_SEND_DATA.data( ), 0.0f, DataRateHelper::MSG_BYTES.data( ) ); + console.outputMsg( NESystemService::COORD_RECV_RATE, NESystemService::FORMAT_RECV_DATA.data( ), 0.0f, DataRateHelper::MSG_BYTES.data( ) ); } mTimer.startTimer( NECommon::TIMEOUT_1_SEC, Timer::CONTINUOUSLY ); @@ -122,14 +96,14 @@ inline void SystemServiceConsole::_outputDataRate(void) { Console& console = Console::getInstance(); console.lockConsole( ); - if ( mSystemService.isVerbose( ) ) + if ( (mDataRateHelper != nullptr) && mDataRateHelper->isVerbose()) { - SystemServiceConsole::DataRate rateSend( mSystemService.queryDataSent( ) ); - SystemServiceConsole::DataRate rateRecv( mSystemService.queryDataReceived( ) ); + DataRateHelper::DataRate rateSend{ mDataRateHelper->queryBytesSentWithLiterals() }; + DataRateHelper::DataRate rateRecv{ mDataRateHelper->queryBytesReceivedWithLiterals() }; console.saveCursorPosition( ); - console.outputMsg( NESystemService::COORD_SEND_RATE, NESystemService::FORMAT_SEND_DATA.data( ), rateSend.mRate.first, rateSend.mRate.second.c_str( ) ); - console.outputMsg( NESystemService::COORD_RECV_RATE, NESystemService::FORMAT_RECV_DATA.data( ), rateRecv.mRate.first, rateRecv.mRate.second.c_str( ) ); + console.outputMsg( NESystemService::COORD_SEND_RATE, NESystemService::FORMAT_SEND_DATA.data( ), rateSend.first, rateSend.second.c_str( ) ); + console.outputMsg( NESystemService::COORD_RECV_RATE, NESystemService::FORMAT_RECV_DATA.data( ), rateRecv.first, rateRecv.second.c_str( ) ); console.restoreCursorPosition( ); console.refreshScreen( ); } diff --git a/framework/extend/service/DataRateHelper.hpp b/framework/extend/service/DataRateHelper.hpp new file mode 100644 index 000000000..382916e89 --- /dev/null +++ b/framework/extend/service/DataRateHelper.hpp @@ -0,0 +1,158 @@ +#ifndef AREG_EXTEND_SERVICE_DATARATEHELPER_HPP +#define AREG_EXTEND_SERVICE_DATARATEHELPER_HPP +/************************************************************************ + * This file is part of the AREG SDK core engine. + * AREG SDK is dual-licensed under Free open source (Apache version 2.0 + * License) and Commercial (with various pricing models) licenses, depending + * on the nature of the project (commercial, research, academic or free). + * You should have received a copy of the AREG SDK license description in LICENSE.txt. + * If not, please contact to info[at]aregtech.com + * + * \copyright (c) 2017-2023 Aregtech UG. All rights reserved. + * \file extend/service/DataRateHelper.hpp + * \ingroup AREG SDK, Automated Real-time Event Grid Software Development Kit + * \author Artak Avetyan + * \brief AREG Platform, Extended features. + * Data rate helper object + ************************************************************************/ + +/************************************************************************ + * Include files. + ************************************************************************/ +#include "areg/base/GEGlobal.h" + +#include "extend/service/private/ServerSendThread.hpp" +#include "extend/service/private/ServerReceiveThread.hpp" + +/************************************************************************ + * Dependencies. + ************************************************************************/ +class ServerSendThread; +class ServerReceiveThread; + +////////////////////////////////////////////////////////////////////////// +// DataRateHelper class declaration. +////////////////////////////////////////////////////////////////////////// +/** + * \brief A simple helper class to calculate data rate. + **/ +class DataRateHelper +{ +////////////////////////////////////////////////////////////////////////// +// Internal types and constants. +////////////////////////////////////////////////////////////////////////// +public: + //!< Bytes in 1 Kilobyte. + static constexpr uint32_t ONE_KILOBYTE { NECommon::ONE_KILOBYTE }; + //!< Bytes in 1 megabyte. + static constexpr uint32_t ONE_MEGABYTE { NECommon::ONE_MEGABYTE }; + //!< String kilobytes per second + static constexpr std::string_view MSG_KILOBYTES { "KBytes / sec." }; + //!< String megabytes per second + static constexpr std::string_view MSG_MEGABYTES { "MBytes / sec." }; + //!< String bytes per second + static constexpr std::string_view MSG_BYTES { " Bytes / sec." }; + + //!< The type of data rate. Contains value and the associated literal. + using DataRate = std::pair; + +////////////////////////////////////////////////////////////////////////// +// Constructor / Destructor. +////////////////////////////////////////////////////////////////////////// +public: + /** + * \brief Initializes the object, sets threads that the rate can be queried. + * If passed 'verbose' parameter is 'false' on each query it returns zero. + * Otherwise, returns the actual value. + * \param sendThread The thread that can be queried the data size sent. + * \param receiveThread The threat that can be queried the data size received. + * \param verbose The flag, indicating whether the actual size should be + * computed or should return zero. + **/ + DataRateHelper(ServerSendThread& sendThread, ServerReceiveThread& receiveThread, bool verbose); + + ~DataRateHelper(void) = default; + +////////////////////////////////////////////////////////////////////////// +// Attributes and actions. +////////////////////////////////////////////////////////////////////////// +public: + + /** + * \brief Sets the verbose state of the helper class. + * \param verbose The verbose flag to set. + **/ + void setVerbose(bool verbose); + + /** + * \brief Returns the verbose flag, indicating whether the data send / receive computation is enabled. + **/ + bool isVerbose(void) const; + + /** + * \brief Return the size in bytes of data sent since last query. + * If verbose flag is false, returns zero. + **/ + inline uint32_t queryBytesSent(void) const; + + /** + * \brief Return the size in bytes of data received since last query. + * If verbose flag is false, returns zero. + **/ + inline uint32_t queryBytesReceived(void) const; + + /** + * \brief Return the size of data sent since last query with literal. + * If verbose flag is false, returns zero. + **/ + inline DataRate queryBytesSentWithLiterals(void) const; + + /** + * \brief Return the size of data received since last query with literal. + * If verbose flag is false, returns zero. + **/ + inline DataRate queryBytesReceivedWithLiterals(void) const; + + //!< This pair contains size in bytes and message indicating MB, KB or Bytes. + static DataRate convertDataRateLiterals(uint32_t sizeBytes); + +////////////////////////////////////////////////////////////////////////// +// Hidden member variables. +////////////////////////////////////////////////////////////////////////// +private: + ServerSendThread & mSendThread; //!< The thread to query the sent data size in bytes. + ServerReceiveThread & mReceiveThread; //!< The thread to query the received data size in bytes. + +////////////////////////////////////////////////////////////////////////// +// Forbidden calls. +////////////////////////////////////////////////////////////////////////// +private: + DataRateHelper(void) = delete; + DECLARE_NOCOPY_NOMOVE(DataRateHelper); +}; + +////////////////////////////////////////////////////////////////////////// +// DataRateHelper class inline methods. +////////////////////////////////////////////////////////////////////////// + +inline uint32_t DataRateHelper::queryBytesSent(void) const +{ + return mSendThread.extractDataSend(); +} + +inline uint32_t DataRateHelper::queryBytesReceived(void) const +{ + return mReceiveThread.extractDataReceive(); +} + +inline DataRateHelper::DataRate DataRateHelper::queryBytesSentWithLiterals(void) const +{ + return DataRateHelper::DataRateHelper::convertDataRateLiterals(queryBytesSent()); +} + +inline DataRateHelper::DataRate DataRateHelper::queryBytesReceivedWithLiterals(void) const +{ + return DataRateHelper::DataRateHelper::convertDataRateLiterals(queryBytesReceived()); +} + +#endif // AREG_EXTEND_SERVICE_DATARATEHELPER_HPP diff --git a/framework/extend/service/ServiceCommunicatonBase.hpp b/framework/extend/service/ServiceCommunicatonBase.hpp index fca0b5874..295703128 100644 --- a/framework/extend/service/ServiceCommunicatonBase.hpp +++ b/framework/extend/service/ServiceCommunicatonBase.hpp @@ -24,15 +24,16 @@ #include "areg/ipc/IEServiceConnectionConsumer.hpp" #include "areg/ipc/IEServiceConnectionProvider.hpp" #include "areg/ipc/ServiceEventConsumerBase.hpp" +#include "extend/service/DataRateHelper.hpp" #include "extend/service/IEServiceConnectionHandler.hpp" -#include "areg/base/Containers.hpp" +#include "areg/base/TEMap.hpp" #include "areg/base/SynchObjects.hpp" #include "areg/component/Timer.hpp" #include "areg/ipc/NERemoteService.hpp" #include "extend/service/ServerConnection.hpp" -#include "extend/service/ServerReceiveThread.hpp" -#include "extend/service/ServerSendThread.hpp" +#include "extend/service/private/ServerReceiveThread.hpp" +#include "extend/service/private/ServerSendThread.hpp" /************************************************************************ * Dependencies @@ -136,18 +137,6 @@ class ServiceCommunicatonBase : public IERemoteMessageHandler **/ inline void removeBlackList( const NESocket::SocketAddress & addrClient ); - /** - * \brief Each time querying the bytes sent via network connection returns - * the value after last query. - **/ - inline uint32_t queryBytesSent(void); - - /** - * \brief Each time querying the bytes received via network connection returns - * the value after last query. - **/ - inline uint32_t queryBytesReceived(void); - /** * \brief Returns the list of connected instances. **/ @@ -166,6 +155,35 @@ class ServiceCommunicatonBase : public IERemoteMessageHandler **/ inline bool sendMessage(const RemoteMessage & data, Event::eEventPriority eventPrio = Event::eEventPriority::EventPriorityNormal ); + /** + * \brief Returns the instance of data rate helper object to use when computing data rate. + **/ + inline DataRateHelper& getDataRateHelper(void) const; + + /** + * \brief Each time querying the bytes sent via network connection returns + * the value after last query. + **/ + inline uint32_t queryBytesSent(void); + + /** + * \brief Each time querying the bytes received via network connection returns + * the value after last query. + **/ + inline uint32_t queryBytesReceived(void); + + /** + * \brief Enable or disable the data rate calculation. + * \param enable If true, the data rate calculation is enabled. + * Otherwise, it is disabled. + **/ + inline void enableCalculateDataRate(bool enable); + + /** + * \brief Returns enable or disable the data rate calculation flag. + **/ + inline bool isCalculateDataRateEnabled(void) const; + ////////////////////////////////////////////////////////////////////////// // overrides ////////////////////////////////////////////////////////////////////////// @@ -350,6 +368,12 @@ class ServiceCommunicatonBase : public IERemoteMessageHandler **/ virtual void onServiceExit(void) override; + /** + * \brief Called when need to inform the channel connection. + * \param cookie The channel connection cookie. + **/ + virtual void onChannelConnected(const ITEM_ID & cookie) override; + /************************************************************************/ // ServiceCommunicatonBase overrides /************************************************************************/ @@ -448,6 +472,7 @@ class ServiceCommunicatonBase : public IERemoteMessageHandler Timer mTimerConnect; //!< The timer object to trigger in case if failed to create server socket. ServerSendThread mThreadSend; //!< The thread to send messages to clients ServerReceiveThread mThreadReceive; //!< The thread to receive messages from clients + DataRateHelper mDataRateHelper; //!< The helper object to query information of sent and receive bytes. StringArray mWhiteList; //!< The list of enabled fixed client hosts. StringArray mBlackList; //!< The list of disabled fixes client hosts. ServiceServerEventConsumer mEventConsumer; //!< The custom event consumer object @@ -505,16 +530,6 @@ inline void ServiceCommunicatonBase::removeBlackList(const NESocket::SocketAddre mBlackList.removeElem( addrClient.getHostAddress(), 0); } -inline uint32_t ServiceCommunicatonBase::queryBytesSent(void) -{ - return mThreadSend.extractDataSend(); -} - -inline uint32_t ServiceCommunicatonBase::queryBytesReceived(void) -{ - return mThreadReceive.extractDataReceive(); -} - inline const ServiceCommunicatonBase::MapInstances & ServiceCommunicatonBase::getInstances( void ) const { return mInstanceMap; @@ -552,6 +567,31 @@ inline bool ServiceCommunicatonBase::sendMessage( const RemoteMessage & data, Ev , eventPrio ); } +inline DataRateHelper& ServiceCommunicatonBase::getDataRateHelper(void) const +{ + return const_cast(mDataRateHelper); +} + +inline uint32_t ServiceCommunicatonBase::queryBytesSent(void) +{ + return mDataRateHelper.queryBytesSent(); +} + +inline uint32_t ServiceCommunicatonBase::queryBytesReceived(void) +{ + return mDataRateHelper.queryBytesReceived(); +} + +inline void ServiceCommunicatonBase::enableCalculateDataRate(bool enable) +{ + mDataRateHelper.setVerbose(enable); +} + +inline bool ServiceCommunicatonBase::isCalculateDataRateEnabled(void) const +{ + return mDataRateHelper.isVerbose(); +} + inline void ServiceCommunicatonBase::disconnectService( Event::eEventPriority eventPrio ) { SendMessageEvent::sendEvent( SendMessageEventData( ) diff --git a/framework/extend/service/SystemServiceBase.hpp b/framework/extend/service/SystemServiceBase.hpp index ec81287da..5ae4b90f3 100644 --- a/framework/extend/service/SystemServiceBase.hpp +++ b/framework/extend/service/SystemServiceBase.hpp @@ -20,7 +20,6 @@ ************************************************************************/ #include "areg/base/GEGlobal.h" -#include "areg/base/SynchObjects.hpp" #include "extend/service/NESystemService.hpp" #include "extend/service/ServiceCommunicatonBase.hpp" @@ -148,25 +147,14 @@ class SystemServiceBase inline NESystemService::eSystemServiceState getState( void ) const; /** - * \brief Resets default options. - **/ - inline void resetDefaultOptions(void); - - /** - * \brief Call to query the size in bytes of data sent. - **/ - inline uint32_t queryDataReceived(void); - - /** - * \brief Call to query the size in bytes of data received. + * \brief Returns the instance of data rate helper object to use when computing data rate. **/ - inline uint32_t queryDataSent(void); + inline DataRateHelper& getDataRateHelper(void) const; /** - * \brief Returns true if verbose flag is set. - * If verbose flag is set, it outputs the data rate in console. + * \brief Resets default options. **/ - inline bool isVerbose( void ) const; + void resetDefaultOptions(void); ////////////////////////////////////////////////////////////////////////// // Overrides @@ -226,10 +214,6 @@ class SystemServiceBase * \brief The current command to execute by message router service. **/ NESystemService::eServiceOption mSystemServiceOption; - /** - * \brief Flag, indicating whether the process should run verbose or not. Valid only if process runs as console application. - */ - bool mRunVerbose; /** * \brief OS specific service handle **/ @@ -255,6 +239,11 @@ inline NESystemService::eSystemServiceState SystemServiceBase::getState( void ) return mSystemServiceState; } +inline DataRateHelper& SystemServiceBase::getDataRateHelper(void) const +{ + return mCommunication.getDataRateHelper(); +} + inline NESystemService::eServiceOption SystemServiceBase::getCurrentOption(void) const { return mSystemServiceOption; @@ -265,25 +254,4 @@ inline void SystemServiceBase::setCurrentOption( NESystemService::eServiceOption mSystemServiceOption = optService; } -inline void SystemServiceBase::resetDefaultOptions(void) -{ - mSystemServiceOption= NESystemService::DEFAULT_OPTION; - mRunVerbose = NESystemService::DEFAULT_VERBOSE; -} - -inline uint32_t SystemServiceBase::queryDataReceived(void) -{ - return mCommunication.queryBytesReceived(); -} - -inline uint32_t SystemServiceBase::queryDataSent(void) -{ - return mCommunication.queryBytesSent(); -} - -inline bool SystemServiceBase::isVerbose(void) const -{ - return mRunVerbose; -} - #endif // AREG_EXTEND_SERVICE_SYSTEMSERVICEBASE_HPP diff --git a/framework/extend/service/private/CMakeLists.txt b/framework/extend/service/private/CMakeLists.txt index 75275f2ed..2f6b32b83 100644 --- a/framework/extend/service/private/CMakeLists.txt +++ b/framework/extend/service/private/CMakeLists.txt @@ -1,4 +1,5 @@ list(APPEND extend_SRC + ${extend_BASE}/service/private/DataRateHelper.cpp ${extend_BASE}/service/private/IEServiceConnectionHandler.cpp ${extend_BASE}/service/private/NESystemService.cpp ${extend_BASE}/service/private/ServerConnection.cpp diff --git a/framework/extend/service/private/DataRateHelper.cpp b/framework/extend/service/private/DataRateHelper.cpp new file mode 100644 index 000000000..b1a5c3af9 --- /dev/null +++ b/framework/extend/service/private/DataRateHelper.cpp @@ -0,0 +1,68 @@ +/************************************************************************ + * This file is part of the AREG SDK core engine. + * AREG SDK is dual-licensed under Free open source (Apache version 2.0 + * License) and Commercial (with various pricing models) licenses, depending + * on the nature of the project (commercial, research, academic or free). + * You should have received a copy of the AREG SDK license description in LICENSE.txt. + * If not, please contact to info[at]aregtech.com + * + * \copyright (c) 2017-2023 Aregtech UG. All rights reserved. + * \file extend/service/private/DataRateHelper.cpp + * \ingroup AREG SDK, Automated Real-time Event Grid Software Development Kit + * \author Artak Avetyan + * \brief AREG Platform, Extended features. + * Data rate helper object + ************************************************************************/ + +/************************************************************************ + * Include files. + ************************************************************************/ +#include "extend/service/DataRateHelper.hpp" + +////////////////////////////////////////////////////////////////////////// +// DataRateHelper class implementation +////////////////////////////////////////////////////////////////////////// + +DataRateHelper::DataRateHelper(ServerSendThread& sendThread, ServerReceiveThread& receiveThread, bool verbose) + : mSendThread (sendThread) + , mReceiveThread(receiveThread) +{ + mSendThread.setEnableCalculateData(verbose); + mReceiveThread.setEnableCalculateData(verbose); +} + +void DataRateHelper::setVerbose(bool verbose) +{ + mSendThread.setEnableCalculateData(verbose); + mReceiveThread.setEnableCalculateData(verbose); +} + +bool DataRateHelper::isVerbose(void) const +{ + return mSendThread.isCalculateDataEnabled() && mReceiveThread.isCalculateDataEnabled(); +} + +DataRateHelper::DataRate DataRateHelper::convertDataRateLiterals(uint32_t sizeBytes) +{ + DataRate dataRate{ 0.0f, "" }; + + if (sizeBytes >= ONE_MEGABYTE) + { + double rate = static_cast(sizeBytes) / ONE_MEGABYTE; + dataRate.first = static_cast(rate); + dataRate.second = DataRateHelper::MSG_MEGABYTES; + } + else if (sizeBytes >= ONE_KILOBYTE) + { + double rate = static_cast(sizeBytes) / ONE_KILOBYTE; + dataRate.first = static_cast(rate); + dataRate.second = DataRateHelper::MSG_KILOBYTES; + } + else + { + dataRate.first = static_cast(sizeBytes); + dataRate.second = DataRateHelper::MSG_BYTES; + } + + return dataRate; +} diff --git a/framework/extend/service/private/Makefile b/framework/extend/service/private/Makefile index b448ab68d..e8405022e 100644 --- a/framework/extend/service/private/Makefile +++ b/framework/extend/service/private/Makefile @@ -1,4 +1,5 @@ extend_SRC += \ + ${extend_BASE}/service/private/DataRateHelper.cpp \ ${extend_BASE}/service/private/IEServiceConnectionHandler.cpp \ ${extend_BASE}/service/private/NESystemService.cpp \ ${extend_BASE}/service/private/ServerConnection.cpp \ diff --git a/framework/extend/service/private/ServerReceiveThread.cpp b/framework/extend/service/private/ServerReceiveThread.cpp index 4ac58d03a..0853987cd 100644 --- a/framework/extend/service/private/ServerReceiveThread.cpp +++ b/framework/extend/service/private/ServerReceiveThread.cpp @@ -12,7 +12,7 @@ * \author Artak Avetyan * \brief AREG Platform, Service connectivity server receive message Thread ************************************************************************/ -#include "extend/service/ServerReceiveThread.hpp" +#include "extend/service/private/ServerReceiveThread.hpp" #include "areg/base/RemoteMessage.hpp" #include "areg/base/SocketAccepted.hpp" @@ -32,6 +32,7 @@ ServerReceiveThread::ServerReceiveThread( IEServiceConnectionHandler & connectHa , mRemoteService ( remoteService ) , mConnection ( connection ) , mBytesReceive ( 0 ) + , mSaveDataReceive ( false ) { } @@ -130,13 +131,17 @@ bool ServerReceiveThread::runDispatcher(void) int sizeReceived = mConnection.receiveMessage(msgReceived, clientSocket); if (sizeReceived > 0 ) { + if (mSaveDataReceive) + { + mBytesReceive += static_cast(sizeReceived); + } + TRACE_DBG("Received message [ %p ] from source [ %p ], client [ %s : %d ]" , static_cast(msgReceived.getMessageId()) , static_cast(msgReceived.getSource()) , addSocket.getHostAddress().getString() , addSocket.getHostPort()); - mBytesReceive += static_cast(sizeReceived); mRemoteService.processReceivedMessage(msgReceived, clientSocket); } else diff --git a/framework/extend/service/ServerReceiveThread.hpp b/framework/extend/service/private/ServerReceiveThread.hpp similarity index 77% rename from framework/extend/service/ServerReceiveThread.hpp rename to framework/extend/service/private/ServerReceiveThread.hpp index e91b19ecf..1b075bf80 100644 --- a/framework/extend/service/ServerReceiveThread.hpp +++ b/framework/extend/service/private/ServerReceiveThread.hpp @@ -1,5 +1,5 @@ -#ifndef AREG_EXTEND_SERVICE_SERVERRECEIVETHREAD_HPP -#define AREG_EXTEND_SERVICE_SERVERRECEIVETHREAD_HPP +#ifndef AREG_EXTEND_SERVICE_PRIVATE_SERVERRECEIVETHREAD_HPP +#define AREG_EXTEND_SERVICE_PRIVATE_SERVERRECEIVETHREAD_HPP /************************************************************************ * This file is part of the AREG SDK core engine. * AREG SDK is dual-licensed under Free open source (Apache version 2.0 @@ -9,7 +9,7 @@ * If not, please contact to info[at]aregtech.com * * \copyright (c) 2017-2023 Aregtech UG. All rights reserved. - * \file extend/service/ServerReceiveThread.hpp + * \file extend/service/private/ServerReceiveThread.hpp * \ingroup AREG SDK, Automated Real-time Event Grid Software Development Kit * \author Artak Avetyan * \brief AREG Platform, Service connectivity server receive message Thread @@ -65,7 +65,19 @@ class ServerReceiveThread : public DispatcherThread * \brief Returns accumulative value of received data size and rests the existing value to zero. * The operations are atomic. The value can be used to display data rate, for example. **/ - inline uint32_t extractDataReceive( void ); + inline uint32_t extractDataReceive( void ) const; + + /** + * \brief Call to enable or disable the received data calculation. + * It as well resets the existing calculated data. + * \param enable Flag, indicating whether data calculation is enabled or not. + **/ + inline void setEnableCalculateData(bool enable); + + /** + * \brief Returns flag, indicating whether data calculation is enabled or not. + **/ + inline bool isCalculateDataEnabled(void) const; protected: /************************************************************************/ @@ -100,7 +112,11 @@ class ServerReceiveThread : public DispatcherThread /** * \brief Accumulative value of received data size. */ - std::atomic_uint mBytesReceive; + mutable std::atomic_uint mBytesReceive; + /** + * \brief Flag, indicating whether data calculation is enabled or disabled. By default, it is disabled. + **/ + bool mSaveDataReceive; ////////////////////////////////////////////////////////////////////////// // Forbidden calls @@ -114,9 +130,23 @@ class ServerReceiveThread : public DispatcherThread // ServerConnection inline methods. ////////////////////////////////////////////////////////////////////////// -inline uint32_t ServerReceiveThread::extractDataReceive(void) +inline uint32_t ServerReceiveThread::extractDataReceive(void) const { return mBytesReceive.exchange(0); } -#endif // AREG_EXTEND_SERVICE_SERVERRECEIVETHREAD_HPP +inline void ServerReceiveThread::setEnableCalculateData(bool enable) +{ + if (mSaveDataReceive != enable) + { + mBytesReceive.store(0u); + mSaveDataReceive = enable; + } +} + +inline bool ServerReceiveThread::isCalculateDataEnabled(void) const +{ + return mSaveDataReceive; +} + +#endif // AREG_EXTEND_SERVICE_PRIVATE_SERVERRECEIVETHREAD_HPP diff --git a/framework/extend/service/private/ServerSendThread.cpp b/framework/extend/service/private/ServerSendThread.cpp index f1e242ed8..eb02bca28 100644 --- a/framework/extend/service/private/ServerSendThread.cpp +++ b/framework/extend/service/private/ServerSendThread.cpp @@ -12,7 +12,7 @@ * \author Artak Avetyan * \brief AREG Platform, Service connectivity server send message thread ************************************************************************/ -#include "extend/service/ServerSendThread.hpp" +#include "extend/service/private/ServerSendThread.hpp" #include "areg/component/NEService.hpp" #include "areg/ipc/private/NEConnection.hpp" @@ -29,6 +29,7 @@ ServerSendThread::ServerSendThread(IERemoteMessageHandler& remoteService, Server , mRemoteService ( remoteService ) , mConnection ( connection ) , mBytesSend ( 0 ) + , mSaveDataSend ( false ) { } @@ -80,7 +81,11 @@ void ServerSendThread::processEvent( const SendMessageEventData & data ) } else { - mBytesSend += sentBytes; + if (mSaveDataSend) + { + mBytesSend += sentBytes; + } + TRACE_DBG("Succeeded to send message [ %u ] to target [ %p ]", msgSend.getMessageId(), static_cast(msgSend.getTarget())); } } diff --git a/framework/extend/service/ServerSendThread.hpp b/framework/extend/service/private/ServerSendThread.hpp similarity index 79% rename from framework/extend/service/ServerSendThread.hpp rename to framework/extend/service/private/ServerSendThread.hpp index f047eae40..2d76c5bf7 100644 --- a/framework/extend/service/ServerSendThread.hpp +++ b/framework/extend/service/private/ServerSendThread.hpp @@ -1,5 +1,5 @@ -#ifndef AREG_EXTEND_SERVICE_SERVERSENDTHREAD_HPP -#define AREG_EXTEND_SERVICE_SERVERSENDTHREAD_HPP +#ifndef AREG_EXTEND_SERVICE_PRIVATE_SERVERSENDTHREAD_HPP +#define AREG_EXTEND_SERVICE_PRIVATE_SERVERSENDTHREAD_HPP /************************************************************************ * This file is part of the AREG SDK core engine. * AREG SDK is dual-licensed under Free open source (Apache version 2.0 @@ -9,7 +9,7 @@ * If not, please contact to info[at]aregtech.com * * \copyright (c) 2017-2023 Aregtech UG. All rights reserved. - * \file extend/service/ServerSendThread.hpp + * \file extend/service/private/ServerSendThread.hpp * \ingroup AREG SDK, Automated Real-time Event Grid Software Development Kit * \author Artak Avetyan * \brief AREG Platform, Service connectivity server send message thread @@ -63,7 +63,19 @@ class ServerSendThread : public DispatcherThread * \brief Returns accumulative value of sent data size and rests the existing value to zero. * The operations are atomic. The value can be used to display data rate, for example. **/ - inline uint32_t extractDataSend( void ); + inline uint32_t extractDataSend( void ) const; + + /** + * \brief Call to enable or disable the received data calculation. + * It as well resets the existing calculated data. + * \param enable Flag, indicating whether data calculation is enabled or not. + **/ + inline void setEnableCalculateData(bool enable); + + /** + * \brief Returns flag, indicating whether data calculation is enabled or not. + **/ + inline bool isCalculateDataEnabled(void) const; protected: /************************************************************************/ @@ -112,15 +124,19 @@ class ServerSendThread : public DispatcherThread /** * \brief The instance of remote servicing interface object **/ - IERemoteMessageHandler& mRemoteService; + IERemoteMessageHandler& mRemoteService; /** * \brief The instance of server connection object **/ - ServerConnection & mConnection; + ServerConnection & mConnection; /** * \brief Accumulative value of sent data size. **/ - std::atomic_uint mBytesSend; + mutable std::atomic_uint mBytesSend; + /** + * \brief Flag, indicating whether should calculate send data size or not. By default it does not compute. + **/ + bool mSaveDataSend; ////////////////////////////////////////////////////////////////////////// // Forbidden calls @@ -134,9 +150,23 @@ class ServerSendThread : public DispatcherThread // ServerSendThread class inline methods ////////////////////////////////////////////////////////////////////////// -inline uint32_t ServerSendThread::extractDataSend(void) +inline uint32_t ServerSendThread::extractDataSend(void) const { return static_cast(mBytesSend.exchange(0)); } -#endif // AREG_EXTEND_SERVICE_SERVERSENDTHREAD_HPP +inline void ServerSendThread::setEnableCalculateData(bool enable) +{ + if (mSaveDataSend != enable) + { + mBytesSend.store(0u); + mSaveDataSend = enable; + } +} + +inline bool ServerSendThread::isCalculateDataEnabled(void) const +{ + return mSaveDataSend; +} + +#endif // AREG_EXTEND_SERVICE_PRIVATE_SERVERSENDTHREAD_HPP diff --git a/framework/extend/service/private/ServiceCommunicatonBase.cpp b/framework/extend/service/private/ServiceCommunicatonBase.cpp index d6ee805b6..1680286bc 100644 --- a/framework/extend/service/private/ServiceCommunicatonBase.cpp +++ b/framework/extend/service/private/ServiceCommunicatonBase.cpp @@ -14,11 +14,14 @@ ************************************************************************/ #include "extend/service/ServiceCommunicatonBase.hpp" +#include "areg/base/DateTime.hpp" #include "areg/ipc/NERemoteService.hpp" #include "areg/ipc/ConnectionConfiguration.hpp" #include "areg/ipc/private/NEConnection.hpp" #include "areg/trace/GETrace.h" +#include "extend/service/NESystemService.hpp" + DEF_TRACE_SCOPE(areg_extend_service_ServiceCommunicatonBase_connectServiceHost); DEF_TRACE_SCOPE(areg_extend_service_ServiceCommunicatonBase_reconnectServiceHost); DEF_TRACE_SCOPE(areg_extend_service_ServiceCommunicatonBase_disconnectServiceHost); @@ -60,6 +63,7 @@ ServiceCommunicatonBase::ServiceCommunicatonBase( const ITEM_ID & serviceId , mTimerConnect ( static_cast(mTimerConsumer), NEConnection::SERVER_CONNECT_TIMER_NAME.data( ) ) , mThreadSend ( static_cast(self()), mServerConnection ) , mThreadReceive ( static_cast(self()), static_cast(self()), mServerConnection ) + , mDataRateHelper ( mThreadSend, mThreadReceive, NESystemService::DEFAULT_VERBOSE ) , mWhiteList ( ) , mBlackList ( ) , mEventConsumer ( self() ) @@ -275,6 +279,10 @@ void ServiceCommunicatonBase::onServiceExit( void ) triggerExit( ); } +void ServiceCommunicatonBase::onChannelConnected(const ITEM_ID& /*cookie*/) +{ +} + bool ServiceCommunicatonBase::startConnection(void) { TRACE_SCOPE(areg_extend_service_ServiceCommunicatonBase_startConnection); @@ -439,6 +447,7 @@ void ServiceCommunicatonBase::processReceivedMessage(const RemoteMessage & msgRe { NEService::sServiceConnectedInstance instance{}; msgReceived >> instance; + instance.ciTimestamp = static_cast(DateTime::getNow()); instance.ciCookie = cookie; addInstance(cookie, instance); RemoteMessage msgConnect(createServiceConnectMessage(mServerConnection.getChannelId(), cookie, NEService::eMessageSource::MessageSourceService)); diff --git a/framework/extend/service/private/SystemServiceBase.cpp b/framework/extend/service/private/SystemServiceBase.cpp index 0760ef681..6d36d15a9 100644 --- a/framework/extend/service/private/SystemServiceBase.cpp +++ b/framework/extend/service/private/SystemServiceBase.cpp @@ -14,15 +14,7 @@ ************************************************************************/ #include "extend/service/SystemServiceBase.hpp" -#include "areg/appbase/Application.hpp" -#include "areg/appbase/NEApplication.hpp" -#include "areg/base/File.hpp" -#include "areg/base/NEUtilities.hpp" -#include "areg/base/Process.hpp" -#include "areg/base/String.hpp" -#include "areg/component/ComponentLoader.hpp" #include "areg/trace/GETrace.h" - #include "extend/console/Console.hpp" @@ -39,12 +31,17 @@ SystemServiceBase::SystemServiceBase( ServiceCommunicatonBase & commBase ) : mCommunication ( commBase ) , mSystemServiceState ( NESystemService::eSystemServiceState::ServiceStopped ) , mSystemServiceOption ( NESystemService::DEFAULT_OPTION ) - , mRunVerbose ( NESystemService::DEFAULT_VERBOSE ) , mSvcHandle ( nullptr ) , mSeMHandle ( nullptr ) { } +void SystemServiceBase::resetDefaultOptions(void) +{ + mSystemServiceOption = NESystemService::DEFAULT_OPTION; + mCommunication.enableCalculateDataRate(NESystemService::DEFAULT_VERBOSE); +} + bool SystemServiceBase::parseOptions( int argc, const char ** argv, const OptionParser::sOptionSetup * optSetup, int optCount ) { bool result{ false }; @@ -71,7 +68,7 @@ bool SystemServiceBase::parseOptions( int argc, const char ** argv, const Option break; case NESystemService::eServiceOption::CMD_Verbose: - mRunVerbose = true; + mCommunication.enableCalculateDataRate(true); setCurrentOption( NESystemService::eServiceOption::CMD_Console ); result = true; break; diff --git a/framework/logger/app/private/Logger.cpp b/framework/logger/app/private/Logger.cpp index c7dc47c5c..ebb02cf5f 100644 --- a/framework/logger/app/private/Logger.cpp +++ b/framework/logger/app/private/Logger.cpp @@ -166,7 +166,7 @@ void Logger::runConsoleInputExtended( void ) Console & console = Console::getInstance( ); Logger::_outputTitle( ); - if ( mRunVerbose ) + if (getDataRateHelper().isVerbose()) { // Disable to block user input until Console Service is up and running. console.enableConsoleInput( false ); @@ -627,9 +627,9 @@ void Logger::_setVerboseMode( bool makeVerbose ) Logger & logger = Logger::getInstance( ); Console & console = Console::getInstance( ); console.lockConsole( ); - if ( logger.mRunVerbose != makeVerbose ) + if ( logger.getDataRateHelper().isVerbose() != makeVerbose ) { - logger.mRunVerbose = makeVerbose; + logger.getDataRateHelper().setVerbose(makeVerbose); if ( makeVerbose == false ) { @@ -639,8 +639,8 @@ void Logger::_setVerboseMode( bool makeVerbose ) } else { - console.outputMsg( NESystemService::COORD_SEND_RATE, NESystemService::FORMAT_SEND_DATA.data( ), 0.0f, SystemServiceConsole::MSG_BYTES.data( ) ); - console.outputMsg( NESystemService::COORD_RECV_RATE, NESystemService::FORMAT_RECV_DATA.data( ), 0.0f, SystemServiceConsole::MSG_BYTES.data( ) ); + console.outputMsg( NESystemService::COORD_SEND_RATE, NESystemService::FORMAT_SEND_DATA.data( ), 0.0f, DataRateHelper::MSG_BYTES.data( ) ); + console.outputMsg( NESystemService::COORD_RECV_RATE, NESystemService::FORMAT_RECV_DATA.data( ), 0.0f, DataRateHelper::MSG_BYTES.data( ) ); console.outputTxt( NESystemService::COORD_INFO_MSG, _verbose); } diff --git a/framework/logger/app/private/LoggerConsoleService.cpp b/framework/logger/app/private/LoggerConsoleService.cpp index c86c02bb0..990af076a 100644 --- a/framework/logger/app/private/LoggerConsoleService.cpp +++ b/framework/logger/app/private/LoggerConsoleService.cpp @@ -37,6 +37,6 @@ void LoggerConsoleService::DeleteComponent( Component & compObject, const NERegi // LoggerConsoleService class implementation ////////////////////////////////////////////////////////////////////////// LoggerConsoleService::LoggerConsoleService( const NERegistry::ComponentEntry & entry, ComponentThread & owner, NEMemory::uAlign OPT data ) - : SystemServiceConsole( static_cast(Logger::getInstance( )), entry, owner, data ) + : SystemServiceConsole( &Logger::getInstance().getDataRateHelper( ), entry, owner, data ) { } diff --git a/framework/logger/service/private/LoggerMessageProcessor.cpp b/framework/logger/service/private/LoggerMessageProcessor.cpp index 52c09e4bd..5b876169a 100644 --- a/framework/logger/service/private/LoggerMessageProcessor.cpp +++ b/framework/logger/service/private/LoggerMessageProcessor.cpp @@ -12,7 +12,6 @@ * \author Artak Avetyan * \brief AREG Platform, Log Collector message processor ************************************************************************/ - #include "logger/service/private/LoggerMessageProcessor.hpp" #include "logger/app/Logger.hpp" @@ -39,24 +38,24 @@ void LoggerMessageProcessor::queryConnectedInstances(const RemoteMessage & msgRe const NEService::sServiceConnectedInstance& instance = instances.valueAtPosition(srcPos); if (instance.ciSource == NEService::eMessageSource::MessageSourceObserver) { - notifyConnectedInstances(source); + notifyConnectedInstances(mLoggerService.getInstances(), source); } } } } -void LoggerMessageProcessor::notifyConnectedInstances(const ITEM_ID& target /*= NEService::COOKIE_ANY*/) const +void LoggerMessageProcessor::notifyConnectedInstances(const ServiceCommunicatonBase::MapInstances& instances, const ITEM_ID& target /*= NEService::COOKIE_ANY*/) const { const auto& observers{ mLoggerService.getObservers() }; if (observers.isEmpty()) return; RemoteMessage msgInstances; - const ServiceCommunicatonBase::MapInstances& instances = mLoggerService.getInstances(); ASSERT((target == NEService::COOKIE_ANY) || (instances.contains(target) && isLogObserver(instances.getAt(target).ciSource))); if (msgInstances.initMessage(NERemoteService::getMessageNotifyInstances().rbHeader) != nullptr) { + msgInstances << NERemoteService::eRemoteConnection::RemoteConnected; uint32_t count{ 0 }; uint32_t pos = msgInstances.getPosition(); msgInstances << count; // reserves space, initially set 0 @@ -93,6 +92,34 @@ void LoggerMessageProcessor::notifyConnectedInstances(const ITEM_ID& target /*= } } +void LoggerMessageProcessor::notifyDisconnectedInstances(const TEArrayList& listIds, const ITEM_ID& target) const +{ + const auto& observers{ mLoggerService.getObservers() }; + if (observers.isEmpty()) + return; + + RemoteMessage msgInstances; + if (msgInstances.initMessage(NERemoteService::getMessageNotifyInstances().rbHeader) != nullptr) + { + msgInstances << NERemoteService::eRemoteConnection::RemoteDisconnected; + msgInstances << listIds; + if (target == NEService::COOKIE_ANY) + { + for (const auto& observer : observers.getData()) + { + RemoteMessage msg{ msgInstances.clone(NEService::COOKIE_LOGGER, observer.first) }; + mLoggerService.sendMessage(msg); + } + } + else + { + msgInstances.setSource(NEService::COOKIE_LOGGER); + msgInstances.setTarget(target); + mLoggerService.sendMessage(msgInstances); + } + } +} + void LoggerMessageProcessor::registerScopesAtObserver(const RemoteMessage & msgReceived) const { ASSERT(msgReceived.getMessageId() == static_cast(NEService::eFuncIdRange::ServiceLogRegisterScopes)); diff --git a/framework/logger/service/private/LoggerMessageProcessor.hpp b/framework/logger/service/private/LoggerMessageProcessor.hpp index e2dc85821..4bc8f87bf 100644 --- a/framework/logger/service/private/LoggerMessageProcessor.hpp +++ b/framework/logger/service/private/LoggerMessageProcessor.hpp @@ -21,6 +21,8 @@ #include "areg/base/GEGlobal.h" #include "areg/component/NEService.hpp" +#include "areg/base/TEArrayList.hpp" +#include "extend/service/ServiceCommunicatonBase.hpp" /************************************************************************ * Dependencies @@ -62,11 +64,26 @@ class LoggerMessageProcessor void queryConnectedInstances(const RemoteMessage & msgReceived) const; /** - * \brief Notifies the observers about connected instances. Automatically processed when - * new instance of application is connected. - * \param msgReceived The message to process. + * \brief Creates a communication message with the information of connected instances + * and sends the notification to the specified observer target. If target is NEService::COOKIE_ANY + * the notification is sent to all connected observers. Otherwise, it send to + * the specified exact target. + * \param instances The list of connected instances to include in the notification message. + * \param target The ID of the target to send the message. If target is NEService::COOKIE_ANY, + * the notification message is sent to all observers. Otherwise, it is sent to the exact target. + **/ + void notifyConnectedInstances(const ServiceCommunicatonBase::MapInstances& instances, const ITEM_ID & target = NEService::COOKIE_ANY) const; + + /** + * \brief Creates a communication message with the IDs of disconnected instances + * and sends the notification to the specified observer target. If target is NEService::COOKIE_ANY + * the notification is sent to all connected observers. Otherwise, it send to + * the specified exact target. + * \param listIds The list of IDs of disconnected instances to include in the notification message. + * \param target The ID of the target to send the message. If target is NEService::COOKIE_ANY, + * the notification message is sent to all observers. Otherwise, it is sent to the exact target. **/ - void notifyConnectedInstances(const ITEM_ID & target = NEService::COOKIE_ANY) const; + void notifyDisconnectedInstances(const TEArrayList & listIds, const ITEM_ID& target = NEService::COOKIE_ANY) const; /** * \brief Called when a connected instance of application requests to register scopes. diff --git a/framework/logger/service/private/LoggerServerService.cpp b/framework/logger/service/private/LoggerServerService.cpp index 1d0363383..9c1566a06 100644 --- a/framework/logger/service/private/LoggerServerService.cpp +++ b/framework/logger/service/private/LoggerServerService.cpp @@ -15,9 +15,7 @@ #include "logger/service/LoggerServerService.hpp" #include "areg/ipc/private/NEConnection.hpp" -#include "areg/ipc/ConnectionConfiguration.hpp" #include "areg/trace/GETrace.h" -#include "areg/trace/private/TraceManager.hpp" DEF_TRACE_SCOPE(logger_service_LoggerServerService_onServiceMessageReceived); DEF_TRACE_SCOPE(logger_service_LoggerServerService_onServiceMessageSend); @@ -34,7 +32,11 @@ DEF_TRACE_SCOPE(logger_service_LoggerServerService_failedReceiveMessage); ////////////////////////////////////////////////////////////////////////// LoggerServerService::LoggerServerService( void ) - : ServiceCommunicatonBase ( NEService::COOKIE_LOGGER, NERemoteService::eRemoteServices::ServiceLogger, static_cast(NERemoteService::eConnectionTypes::ConnectTcpip), NEConnection::SERVER_DISPATCH_MESSAGE_THREAD, ServiceCommunicatonBase::eConnectionBehavior::DefaultAccept ) + : ServiceCommunicatonBase ( NEService::COOKIE_LOGGER + , NERemoteService::eRemoteServices::ServiceLogger + , static_cast(NERemoteService::eConnectionTypes::ConnectTcpip) + , NEConnection::SERVER_DISPATCH_MESSAGE_THREAD + , ServiceCommunicatonBase::eConnectionBehavior::DefaultAccept ) , mLoggerProcessor ( self() ) , mObservers ( ) { @@ -57,7 +59,7 @@ void LoggerServerService::addInstance(const ITEM_ID& cookie, const NEService::sS , instance.ciLocation.getString()); NETrace::logAnyMessageLocal(logMsgHello); - mLoggerProcessor.notifyConnectedInstances(NEService::COOKIE_ANY); + mLoggerProcessor.notifyConnectedInstances(getInstances(), NEService::COOKIE_ANY); } else if (LoggerMessageProcessor::isLogObserver(instance.ciSource)) { @@ -69,6 +71,7 @@ void LoggerServerService::removeInstance(const ITEM_ID & cookie) { Lock lock(mLock); + TEArrayList listIds; NEService::sServiceConnectedInstance instance; bool exists{ mInstanceMap.find(cookie, instance) }; ServiceCommunicatonBase::removeInstance(cookie); @@ -85,7 +88,8 @@ void LoggerServerService::removeInstance(const ITEM_ID & cookie) , instance.ciLocation.getString()); NETrace::logAnyMessageLocal(logMsgBye); - mLoggerProcessor.notifyConnectedInstances(NEService::COOKIE_ANY); + listIds.add(instance.ciCookie); + mLoggerProcessor.notifyDisconnectedInstances(listIds, NEService::COOKIE_ANY); } else if (LoggerMessageProcessor::isLogObserver(instance.ciSource)) { @@ -98,11 +102,24 @@ void LoggerServerService::removeAllInstances(void) Lock lock(mLock); if (mInstanceMap.getSize() != 0) { + TEArrayList listIds; + for (const auto& entry : getInstances().getData()) + { + if (LoggerMessageProcessor::isLogSource(entry.second.ciSource)) + { + listIds.add(entry.second.ciCookie); + } + } + NETrace::sLogMessage logMsgClose(NETrace::eLogMessageType::LogMessageText, 0, NETrace::eLogPriority::PrioAny, nullptr, 0); String::formatString(logMsgClose.logMessage, NETrace::LOG_MESSAGE_IZE, "Disconnecting and removing [ %u ] instances.", mInstanceMap.getSize()); NETrace::logAnyMessageLocal(logMsgClose); ServiceCommunicatonBase::removeAllInstances(); - mLoggerProcessor.notifyConnectedInstances(NEService::COOKIE_ANY); + + if (listIds.isEmpty() == false) + { + mLoggerProcessor.notifyDisconnectedInstances(listIds, NEService::COOKIE_ANY); + } } mObservers.clear(); diff --git a/framework/logobserver.vcxproj b/framework/logobserver.vcxproj new file mode 100644 index 000000000..8f9a14710 --- /dev/null +++ b/framework/logobserver.vcxproj @@ -0,0 +1,62 @@ + + + + + + + + + + {6941F2A7-F0C7-4293-8646-AF68A7E35183} + logobserver + logobserver + Win32Proj + + + + Application + + + + + + + IMPORT_SHARED_SYMBOLS;IMP_OBSERVER_DLL;%(PreprocessorDefinitions) + + + Console + + + + + true + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/framework/logobserver.vcxproj.filters b/framework/logobserver.vcxproj.filters new file mode 100644 index 000000000..22b3eae12 --- /dev/null +++ b/framework/logobserver.vcxproj.filters @@ -0,0 +1,62 @@ + + + + + {D793B7F9-5C7D-4377-87BB-C518A38775F6} + cpp;c;cc;cxx;def;odl;idl;hpj;asm;asmx + + + {3E8CF3D1-AB38-487A-ACA2-0B418564F19A} + h;hpp;hxx;hm;inl;inc;xsd + + + {FE470092-6909-4506-9FD7-6E5F1B182FCF} + bat;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + + + + + Resource Files + + + Resource Files + + + + + Resource Files + + + \ No newline at end of file diff --git a/framework/mcrouter/app/private/MulticastRouter.cpp b/framework/mcrouter/app/private/MulticastRouter.cpp index 670ed57f5..ec17ade6f 100644 --- a/framework/mcrouter/app/private/MulticastRouter.cpp +++ b/framework/mcrouter/app/private/MulticastRouter.cpp @@ -18,11 +18,9 @@ #include "areg/appbase/Application.hpp" #include "areg/appbase/NEApplication.hpp" -#include "areg/base/File.hpp" -#include "areg/base/NEUtilities.hpp" +#include "areg/component/ComponentLoader.hpp" #include "areg/base/Process.hpp" #include "areg/base/String.hpp" -#include "areg/component/ComponentLoader.hpp" #include "areg/trace/GETrace.h" #include "extend/console/Console.hpp" @@ -120,7 +118,6 @@ std::pair MulticastRouter::getOptionSet return std::pair< const OptionParser::sOptionSetup *, int>(MulticastRouter::ValidOptions, static_cast(MACRO_ARRAYLEN( MulticastRouter::ValidOptions ))); } - MulticastRouter::MulticastRouter( void ) : SystemServiceBase ( mServiceServer ) , mServiceServer ( ) @@ -144,7 +141,7 @@ void MulticastRouter::runConsoleInputExtended( void ) Console & console = Console::getInstance( ); MulticastRouter::_outputTitle( ); - if ( mRunVerbose ) + if (getDataRateHelper().isVerbose()) { // Disable to block user input until Console Service is up and running. console.enableConsoleInput( false ); @@ -569,9 +566,9 @@ void MulticastRouter::_setVerboseMode( bool makeVerbose ) MulticastRouter & router = MulticastRouter::getInstance( ); Console & console = Console::getInstance( ); console.lockConsole( ); - if ( router.mRunVerbose != makeVerbose ) + if ( router.getDataRateHelper().isVerbose() != makeVerbose ) { - router.mRunVerbose = makeVerbose; + router.getDataRateHelper().setVerbose(makeVerbose); if ( makeVerbose == false ) { @@ -581,8 +578,8 @@ void MulticastRouter::_setVerboseMode( bool makeVerbose ) } else { - console.outputMsg( NESystemService::COORD_SEND_RATE, NESystemService::FORMAT_SEND_DATA.data( ), 0.0f, SystemServiceConsole::MSG_BYTES.data( ) ); - console.outputMsg( NESystemService::COORD_RECV_RATE, NESystemService::FORMAT_RECV_DATA.data( ), 0.0f, SystemServiceConsole::MSG_BYTES.data( ) ); + console.outputMsg( NESystemService::COORD_SEND_RATE, NESystemService::FORMAT_SEND_DATA.data( ), 0.0f, DataRateHelper::MSG_BYTES.data( ) ); + console.outputMsg( NESystemService::COORD_RECV_RATE, NESystemService::FORMAT_RECV_DATA.data( ), 0.0f, DataRateHelper::MSG_BYTES.data( ) ); console.outputTxt( NESystemService::COORD_INFO_MSG, _verbose); } diff --git a/framework/mcrouter/app/private/RouterConsoleService.cpp b/framework/mcrouter/app/private/RouterConsoleService.cpp index 4dc4b9d34..1b9a3359f 100644 --- a/framework/mcrouter/app/private/RouterConsoleService.cpp +++ b/framework/mcrouter/app/private/RouterConsoleService.cpp @@ -37,6 +37,6 @@ void RouterConsoleService::DeleteComponent( Component & compObject, const NERegi // RouterConsoleService class implementation ////////////////////////////////////////////////////////////////////////// RouterConsoleService::RouterConsoleService( const NERegistry::ComponentEntry & entry, ComponentThread & owner, NEMemory::uAlign OPT data ) - : SystemServiceConsole( static_cast(MulticastRouter::getInstance()), entry, owner, data ) + : SystemServiceConsole( &MulticastRouter::getInstance().getDataRateHelper(), entry, owner, data) { } diff --git a/framework/observer/CMakeLists.txt b/framework/observer/CMakeLists.txt index 7c9bccd0e..7fbc463dc 100644 --- a/framework/observer/CMakeLists.txt +++ b/framework/observer/CMakeLists.txt @@ -1,3 +1,4 @@ set(observer_BASE "${AREG_BASE}/observer") include("${observer_BASE}/lib/CMakeLists.txt") +include("${observer_BASE}/app/CMakeLists.txt") diff --git a/framework/observer/Makefile b/framework/observer/Makefile index 3b435a723..3561566e4 100644 --- a/framework/observer/Makefile +++ b/framework/observer/Makefile @@ -1,7 +1,15 @@ observer_BASE := $(AREG_BASE)/observer +logobserver_TARGET_BIN := +observer_lib_TARGET_BIN := + +OBSERVER_API_IMPORT := +OBSERVER_API_PATH := + include $(observer_BASE)/lib/Makefile +include $(observer_BASE)/app/Makefile + -observer: observerapi +observer: observerapi logobserver -.PHONY: observerapi +.PHONY: observer diff --git a/framework/observer/app/CMakeLists.txt b/framework/observer/app/CMakeLists.txt new file mode 100644 index 000000000..4d2458d37 --- /dev/null +++ b/framework/observer/app/CMakeLists.txt @@ -0,0 +1,5 @@ +set(logobserver_BASE "${AREG_BASE}/observer") +set(logobserver_RESOURCE "${logobserver_BASE}/resources") +set(logobserver_SRC) + +include("${logobserver_BASE}/app/private/CMakeLists.txt") diff --git a/framework/observer/app/LogObserver.hpp b/framework/observer/app/LogObserver.hpp new file mode 100644 index 000000000..a59e7171b --- /dev/null +++ b/framework/observer/app/LogObserver.hpp @@ -0,0 +1,298 @@ +#ifndef AREG_LOGOBSERVER_APP_LOGOBSERVER_HPP +#define AREG_LOGOBSERVER_APP_LOGOBSERVER_HPP +/************************************************************************ + * This file is part of the AREG SDK core engine. + * AREG SDK is dual-licensed under Free open source (Apache version 2.0 + * License) and Commercial (with various pricing models) licenses, depending + * on the nature of the project (commercial, research, academic or free). + * You should have received a copy of the AREG SDK license description in LICENSE.txt. + * If not, please contact to info[at]aregtech.com + * + * \copyright (c) 2017-2023 Aregtech UG. All rights reserved. + * \file observer/app/LogObserver.hpp + * \ingroup AREG SDK, Automated Real-time Event Grid Software Development Kit + * \author Artak Avetyan + * \brief AREG Platform, logger to run as a console application process or service. + ************************************************************************/ + +/************************************************************************ + * Include files. + ************************************************************************/ +#include "observer/app/NELogObserverSettings.hpp" +#include "areg/persist/IEConfigurationListener.hpp" + +#include "areg/base/SynchObjects.hpp" +#include "extend/console/Console.hpp" +#include "extend/console/OptionParser.hpp" + +#include + +/************************************************************************ + * Dependencies. + ************************************************************************/ +struct sLogInstance; +struct sLogMessage; +struct sLogScope; + +////////////////////////////////////////////////////////////////////////// +// LogObserver class declaration +////////////////////////////////////////////////////////////////////////// +/** + * \brief The LogObserver service is a separate process, which receives + * and collects the log messages from the running applications. + * It may save logs in the file or forward to log viewer application.. + **/ +class LogObserver +{ +////////////////////////////////////////////////////////////////////////// +// Internal types +////////////////////////////////////////////////////////////////////////// +private: + /** + * \brief The commands to handle the logger. + **/ + enum class eLoggerOptions : int32_t + { + CMD_LogUndefined //!< Undefined command. + , CMD_LogQueryScopes //!< Query the list of scopes + , CMD_LogSaveConfig //!< Save the configuration file. + , CMD_LogPrintHelp //!< Output help message. + , CMD_LogInformation //!< Display the list of logging source instances. + , CMD_LogUpdateScope //!< Set and update the log scope priorities. + , CMD_LogPause //!< Pause log observer. + , CMD_LogQuit //!< Quit log observer. + , CMD_LogRestart //!< Restart / continue log observer . + , CMD_LogStop //!< Stop log observer. + }; + + /** + * \brief The setup to validate input options of the logger. + **/ + static const OptionParser::sOptionSetup ValidOptions[ ]; + +////////////////////////////////////////////////////////////////////////// +// statics +////////////////////////////////////////////////////////////////////////// +public: + /** + * \brief Returns singleton instance of the LogObserver. + **/ + static LogObserver& getInstance( void ); + +////////////////////////////////////////////////////////////////////////// +// Hidden constructor / destructor +////////////////////////////////////////////////////////////////////////// +private: + /** + * \brief Default constructor and destructor. + **/ + LogObserver( void ) = default; + ~LogObserver(void) = default; + +////////////////////////////////////////////////////////////////////////// +// Attributes and operations +////////////////////////////////////////////////////////////////////////// +public: + + /** + * \brief Called from main to start execution of message router service. + * \param argc The 'argc' parameter passed from 'main', indicates the number of parameters passed to executable. + * \param argv The 'argv' parameter passed from 'main', indicated parameters passed to executable. + **/ + void logMain( int argc, char ** argv ); + + /** + * \brief Triggered to receive a function to validate and check the input option values. + **/ + Console::CallBack getOptionCheckCallback( void ) const; + +private: + + /** + * \brief The callback of the event triggered when initializing and configuring the observer. + * The callback indicates the IP address and port number of the logger service set + * in the configuration file. + * \param address The null-terminated string of the IP address of the logger service set in the configuration file. + * \param port The IP port number of the logger service set in the configuration file. + **/ + static void callbackObserverConfigured(const char * address, uint16_t port); + + /** + * \brief The callback of the event triggered when the observer connects or disconnects from the logger service. + * \param isConnected Flag, indicating whether observer is connected or disconnected. + * \param address The IP address of the logger service to connect or disconnect. + * \param port The IP port number of the logger service to connect or disconnect. + **/ + static void callbackServiceConnected(bool isConnected, const char* address, uint16_t port); + + /** + * \brief The callback of the event trigger when starting or pausing the log observer. + * If the log observer is paused, on start it continues to write logs in the same file. + * If the log observer is stopped (disconnected is called), on start it creates new file. + * \param isStarted The flag indicating whether the lob observer is started or paused. + **/ + static void callbackObserverStarted(bool isStarted); + + /** + * \brief The callback of the event triggered when fails to send or receive message. + **/ + static void callbackMessagingFailed(void); + + /** + * \brief The callback of the event triggered when receive the list of connected instances that make logs. + * \param instances The pointer to the list of the connected instances. + * \param count The number of entries in the list. + **/ + static void callbackConnectedInstances(const sLogInstance* instances, uint32_t count); + + /** + * \brief The callback of the event triggered when receive the list of disconnected instances that make logs. + * \param instances The pointer to the list of IDs of the disconnected instances. + * \param count The number of entries in the list. + **/ + static void callbackDisconnecteInstances(const ITEM_ID * instances, uint32_t count); + + /** + * \brief The callback of the event triggered when receive the list of the scopes registered in an application. + * \param cookie The cookie ID of the connected instance / application. Same as sLogInstance::liCookie + * \param scopes The list of the scopes registered in the application. Each entry contains the ID of the scope, message priority and the full name. + * \param count The number of scope entries in the list. + **/ + static void callbackLogScopes(ITEM_ID cookie, const sLogScope* scopes, uint32_t count); + + /** + * \brief The callback of the event triggered when receive remote message to log. + * The buffer indicates to the NETrace::sLogMessage structure. + * \param logBuffer The pointer to the NETrace::sLogMessage structure to log messages. + * \param size The size of the buffer with log message. + **/ + static void callbackLogMessageEx(const unsigned char * logBuffer, uint32_t size); + +////////////////////////////////////////////////////////////////////////// +// Hidden methods. +////////////////////////////////////////////////////////////////////////// +private: + /** + * \brief Triggered if need to run console with extended features. + * In extended feature, the console can output message at any position on the screen. + **/ + void _runConsoleInputExtended(void); + + /** + * \brief Enables or disables local log messages of the current process. + * The method does not enable or disable logging, it only enables logging messages, + * i.e. sets the priority NOTSET. + * \param config Instance of the configuration manager to enable or disable log messages. + * \param enable Flag, indicating whether the logs should be enabled or not. + * If true, the logs are enabled. Otherwise, the logs are disabled. + **/ + inline void enableLocalLogs(ConfigManager& config, bool enable); + + /** + * \brief Checks the command typed on console. Relevant only if it runs as a console application. + * \param cmd The command typed on the console. + * \return Returns true if command is recognized. Otherwise, returns false. + **/ + static bool _checkCommand(const String& cmd); + + /** + * \brief Output on console the title. + **/ + static void _outputTitle( void ); + + /** + * \brief Prints info on console. + **/ + static void _outputInfo( const String & info ); + + /** + * \brief Call to clean all message outputs like help, prompt, etc. + * Normally, help is the largest message. + **/ + static void _cleanHelp(void); + + /** + * \brief Triggered when requested to save the configuration of the client(s). + * \param optSave The option entry that contains the list of target clients + * that should save configuration. + **/ + static void _processSaveConfig(const OptionParser::sOption& optSave); + + /** + * \brief Triggered to print the help message on console. + * \param isCmdLine Flag indicating whether it should print the help + * of using service in command line or help of user input commands. + * If 'true', the printing message is about using the service in + * command line. Otherwise, if application expects user inputs, prints + * the help of command options. + **/ + static void _processPrintHelp(void); + + /** + * \brief Triggered to print the information of instances, such as ID, number of registered scope, name, etc. + **/ + static void _processInfoInstances(void); + + /** + * \brief Triggered to process update scope priority command. + * \param optScope The option entry that contains scope priority update instruction. + * If the command contains a list of scopes to update, the should be split by ';'. + **/ + static void _processUpdateScopes(const OptionParser::sOption& optScope); + + /** + * \brief Triggered to pause logging. The lob observer is paused if it does not write logs in the file. + * But the log observer may remain connected. + **/ + static void _processPauseLogging(void); + + /** + * \brief Triggered to stop, resume or start logging. When starts it may create new log file. + * The resumed logging continues writing logs in the existing log file. + * \param doStart If true it resumes or starts the logging. + * If false, it stops and disconnects the log observer from logging service. + **/ + static void _processStartLogging(bool doStart); + + /** + * \brief Triggered to trigger querying the list of registered scopes. + * \param optScope The option entry that contains query command and list of client application IDs to request scope list. + * If the command contains a list of IDs, it can be separated either by space ' ' or semicolon ';'. + **/ + static void _processQueryScopes(const OptionParser::sOption& optScope); + + /** + * \brief Normalizes the scope to make it suitable to generate property object with the key and value. + * \param scope The scope to normalize. + * \return Returns normalized scope priority string to parse and generate property object with key and value. + **/ + static String _normalizeScopeProperty(const String & scope); + + /** + * \brief Creates a scope update message to send to the target client. + * \param scope The scope priority string to parse and create message. + * \return Returns message to send to the remote target client. + **/ + static RemoteMessage _sendScopeUpdateMessage(const String& scope); + +////////////////////////////////////////////////////////////////////////// +// OS specific hidden methods. +////////////////////////////////////////////////////////////////////////// +private: + + /** + * \brief OS specific implementation of waiting for user input on console. + * \param buffer The allocated buffer to stream input from console. + * \param bufSize The size of allocated bugger. + * \return Returns true if succeeded to get user input. + **/ + bool _osWaitUserInput(char* buffer, unsigned int bufSize); + +////////////////////////////////////////////////////////////////////////// +// Forbidden calls +////////////////////////////////////////////////////////////////////////// +private: + DECLARE_NOCOPY_NOMOVE( LogObserver ); +}; + +#endif // AREG_LOGOBSERVER_APP_LOGOBSERVER_HPP diff --git a/framework/observer/app/Makefile b/framework/observer/app/Makefile new file mode 100644 index 000000000..7cc19b265 --- /dev/null +++ b/framework/observer/app/Makefile @@ -0,0 +1,26 @@ +logobserver_PROJECT_NAME := logobserver + +logobserver_BASE := $(AREG_BASE)/observer +logobserver_OUTPUT_OBJ := $(AREG_OUTPUT_OBJ)/$(logobserver_PROJECT_NAME) + +logobserver_SRC := +logobserver_OBJS := + +include $(logobserver_BASE)/app/private/Makefile + +logobserver_CXXFLAGS := -I$(AREG_BASE) -D$(AREG_LIB_IMPORT) $(OBSERVER_API_IMPORT) +logobserver_LDFLAGS := -L$(OBSERVER_API_PATH) $(AREG_TOOL_FLAGS) -l$(observer_lib_PROJECT_NAME) +logobserver_TARGET_BIN := $(AREG_OUTPUT_BIN)/$(logobserver_PROJECT_NAME)$(AREG_BIN_EXT) + +logobserver: $(logobserver_TARGET_BIN) + +# define one target for each source file +$(foreach cpp, $(logobserver_SRC), $(eval $(call obj, $(cpp), $(logobserver_OUTPUT_OBJ), logobserver_OBJS, $(logobserver_CXXFLAGS)))) + +DEPS = $(logobserver_OBJS:%.o=%.d) +-include $(DEPS) + +$(logobserver_TARGET_BIN): $(areg_TARGET_PATH) $(logobserver_OBJS) $(AREG_DEPEND) $(observer_lib_TARGET_BIN) + @echo "Linking log observer ..." + @mkdir -p $(dir $@) + $(AREG_TOOLCHAIN) $(CXXFLAGS) $(logobserver_CXXFLAGS) $(logobserver_OBJS) -o $@ $(logobserver_LDFLAGS) diff --git a/framework/observer/app/NELogObserverSettings.hpp b/framework/observer/app/NELogObserverSettings.hpp new file mode 100644 index 000000000..53f314947 --- /dev/null +++ b/framework/observer/app/NELogObserverSettings.hpp @@ -0,0 +1,63 @@ +#ifndef AREG_LOGOBSERVER_APP_NELOGOBSERVERSETTINGS_HPP +#define AREG_LOGOBSERVER_APP_NELOGOBSERVERSETTINGS_HPP +/************************************************************************ + * This file is part of the AREG SDK core engine. + * AREG SDK is dual-licensed under Free open source (Apache version 2.0 + * License) and Commercial (with various pricing models) licenses, depending + * on the nature of the project (commercial, research, academic or free). + * You should have received a copy of the AREG SDK license description in LICENSE.txt. + * If not, please contact to info[at]aregtech.com + * + * \copyright (c) 2017-2023 Aregtech UG. All rights reserved. + * \file observer/app/NELogObserverSettings.hpp + * \ingroup AREG SDK, Automated Real-time Event Grid Software Development Kit + * \author Artak Avetyan + * \brief AREG Platform, Log Observer console application, + * Log Observer Settings. + ************************************************************************/ + +#if !defined(IMP_AREG_DLL) && !defined(IMP_AREG_LIB) && !defined(IMPORT_SHARED_SYMBOLS) && !defined(IMPORT_STATIC_SYMBOLS) + #define IMP_AREG_DLL +#elif defined(IMP_AREG_DLL) || defined(IMPORT_SHARED_SYMBOLS) + #undef IMP_AREG_DLL + #define IMP_AREG_DLL +#elif defined(IMP_AREG_LIB) || defined(IMPORT_STATIC_SYMBOLS) + #undef IMP_AREG_LIB + #define IMP_AREG_LIB +#endif // !defined(IMP_AREG_DLL) && !defined(IMP_AREG_LIB) && !defined(IMPORT_SHARED_SYMBOLS) && !defined(IMPORT_STATIC_SYMBOLS) + +#if !defined(IMP_OBSERVER_DLL) && !defined(IMP_OBSERVER_LIB) + #define IMP_OBSERVER_DLL +#endif // !defined(IMP_OBSERVER_DLL) || !defined(IMP_OBSERVER_LIB) + +#if 0 +#if !defined(AREG_EXTENDED) + #define AREG_EXTENDED 1 +#elif (AREG_EXTENDED == 0) + #undef AREG_EXTENDED + #define AREG_EXTENDED 1 +#endif // !defined(AREG_EXTENDED) +#endif + +/************************************************************************ + * Include files. + ************************************************************************/ +#include "observer/lib/LogObserverSwitches.h" + +#include + +namespace NELogObserverSettings +{ + /** + * \brief The name of main thread in the console log observer application. + **/ + constexpr char LOG_OBSERVER_THREAD_NAME[] { "_AREG_LOG_OBSERVER_THREAD_" }; + + /** + * \brief The title to display on console when run application. + **/ + constexpr std::string_view APP_TITLE{ "AREG Log Observer console application ..." }; + +} + +#endif // AREG_LOGOBSERVER_APP_NELOGOBSERVERSETTINGS_HPP diff --git a/framework/observer/app/private/CMakeLists.txt b/framework/observer/app/private/CMakeLists.txt new file mode 100644 index 000000000..08d673b39 --- /dev/null +++ b/framework/observer/app/private/CMakeLists.txt @@ -0,0 +1,6 @@ +list(APPEND logobserver_SRC + ${logobserver_BASE}/app/private/LogObserver.cpp + ${logobserver_BASE}/app/private/NELogObserverSettings.cpp + ${logobserver_BASE}/app/private/posix/LogObserverPosix.cpp + ${logobserver_BASE}/app/private/win32/LogObserverWin32.cpp +) diff --git a/framework/observer/app/private/LogObserver.cpp b/framework/observer/app/private/LogObserver.cpp new file mode 100644 index 000000000..efa03772d --- /dev/null +++ b/framework/observer/app/private/LogObserver.cpp @@ -0,0 +1,670 @@ +/************************************************************************ + * This file is part of the AREG SDK core engine. + * AREG SDK is dual-licensed under Free open source (Apache version 2.0 + * License) and Commercial (with various pricing models) licenses, depending + * on the nature of the project (commercial, research, academic or free). + * You should have received a copy of the AREG SDK license description in LICENSE.txt. + * If not, please contact to info[at]aregtech.com + * + * \copyright (c) 2017-2023 Aregtech UG. All rights reserved. + * \file observer/app/private/LogObserver.cpp + * \ingroup AREG SDK, Automated Real-time Event Grid Software Development Kit + * \author Artak Avetyan + * \brief AREG Platform, logger to run as a console application process or service. + ************************************************************************/ + +/************************************************************************ + * Include files. + ************************************************************************/ +#include "observer/app/LogObserver.hpp" + +#include "areg/appbase/Application.hpp" +#include "areg/base/DateTime.hpp" +#include "areg/base/String.hpp" +#include "areg/persist/ConfigManager.hpp" + +#include "extend/service/NESystemService.hpp" + +#include "observer/lib/LogObserverApi.h" + +#include + +////////////////////////////////////////////////////////////////////////// +// The model used only in console mode. +////////////////////////////////////////////////////////////////////////// + +// This model defines a Console Service to run to make data rate outputs. +// The Console Service runs only in verbose mode. + +namespace +{ + constexpr std::string_view _msgHelp [] + { + {"Usage of AREG Log Observer console application :"} + , NESystemService::MSG_SEPARATOR + , {"-e, --query : Query the list of logging scopes. Usage: --query *, \'*\' can be a cookie ID."} + , {"-f, --config : Save current configuration. Usage: --config"} + , {"-h, --help : Display this message on console. Usage: --help"} + , {"-i, --info : Display list of log instances. Usage: --info"} + , {"-o, --scope : Update log scope priorities. Usage: --scope *::areg_base_NESocket=NOTSET, \'*\' can be a cookie."} + , {"-p, --pause : Pause the log observer. Usage: --pause"} + , {"-q, --quit : Stop and quit the log observer. Usage: --quit"} + , {"-r, --restart : Start / continue log observer. Usage: --restart"} + , {"-s, --stop : Stop log observer. Usage: --stop"} + , NESystemService::MSG_SEPARATOR + }; + + struct sLoggerConnect + { + String lcAddress; + uint16_t lcPort{ NESocket::InvalidPort }; + }; + + using ListInstances = TEArrayList; + using ListScopes = TEArrayList; + using MapScopes = TEHashMap; + + sLoggerConnect _logConnect; + ListInstances _listInstances; + MapScopes _mapScopes; + +} + +////////////////////////////////////////////////////////////////////////// +// LogObserver class implementation +////////////////////////////////////////////////////////////////////////// + +const OptionParser::sOptionSetup LogObserver::ValidOptions[ ] +{ + { "-e", "--query" , static_cast(eLoggerOptions::CMD_LogQueryScopes) , OptionParser::STRING_NO_RANGE , {}, {}, {} } + , { "-f", "--config" , static_cast(eLoggerOptions::CMD_LogSaveConfig) , OptionParser::STRING_NO_RANGE , {}, {}, {} } + , { "-h", "--help" , static_cast(eLoggerOptions::CMD_LogPrintHelp) , OptionParser::NO_DATA , {}, {}, {} } + , { "-i", "--info" , static_cast(eLoggerOptions::CMD_LogInformation) , OptionParser::NO_DATA , {}, {}, {} } + , { "-o", "--scope" , static_cast(eLoggerOptions::CMD_LogUpdateScope) , OptionParser::STRING_NO_RANGE , {}, {}, {} } + , { "-p", "--pause" , static_cast(eLoggerOptions::CMD_LogPause) , OptionParser::NO_DATA , {}, {}, {} } + , { "-q", "--quit" , static_cast(eLoggerOptions::CMD_LogQuit) , OptionParser::NO_DATA , {}, {}, {} } + , { "-r", "--restart" , static_cast(eLoggerOptions::CMD_LogRestart) , OptionParser::NO_DATA , {}, {}, {} } + , { "-s", "--stop" , static_cast(eLoggerOptions::CMD_LogStop) , OptionParser::NO_DATA , {}, {}, {} } +}; + +LogObserver & LogObserver::getInstance(void) +{ + static LogObserver _instance; + return _instance; +} + +Console::CallBack LogObserver::getOptionCheckCallback( void ) const +{ + return Console::CallBack( LogObserver::_checkCommand ); +} + +void LogObserver::_runConsoleInputExtended( void ) +{ + Console & console = Console::getInstance( ); + LogObserver::_outputTitle( ); + + console.enableConsoleInput(true); + console.outputTxt(NESystemService::COORD_USER_INPUT, NESystemService::FORMAT_WAIT_QUIT); + console.waitForInput(getOptionCheckCallback()); + + console.moveCursorOneLineDown( ); + console.clearScreen( ); + console.uninitialize( ); +} + +void LogObserver::callbackObserverConfigured(const char* address, uint16_t port) +{ +} + +void LogObserver::callbackServiceConnected(bool isConnected, const char* address, uint16_t port) +{ + if (isConnected) + { + _logConnect.lcAddress = address; + _logConnect.lcPort = port; + } + else + { + _logConnect.lcAddress.clear(); + _logConnect.lcPort = NESocket::InvalidPort; + } +} + +void LogObserver::callbackObserverStarted(bool isStarted) +{ +} + +void LogObserver::callbackMessagingFailed(void) +{ +} + +void LogObserver::callbackConnectedInstances(const sLogInstance* instances, uint32_t count) +{ + if (count == 0) + { + _listInstances.clear(); + _mapScopes.clear(); + return; + } + + for (uint32_t i = 0; i < count; ++i) + { + const sLogInstance& inst{ instances[i] }; + bool contains{ false }; + for (uint32_t j = 0; j < _listInstances.getSize(); ++j) + { + if (_listInstances[j].liCookie == inst.liCookie) + { + contains = true; + break; + } + } + + if (contains == false) + { + NETrace::sLogMessage log{ }; + log.logDataType = NETrace::eLogDataType::LogDataLocal; + log.logMsgType = NETrace::eLogMessageType::LogMessageText; + log.logMessagePrio = NETrace::eLogPriority::PrioAny; + log.logSource = inst.liSource; + log.logTarget = NEService::COOKIE_LOCAL; + log.logCookie = inst.liCookie; + log.logModuleId = 0u; + log.logThreadId = 0u; + log.logTimestamp = inst.liTimestamp; + log.logScopeId = 0u; + log.logMessageLen = String::formatString(log.logMessage, NETrace::LOG_MESSAGE_IZE, "CONNECTED the x%u instance %s with cookie %llu", inst.liBitness, inst.liName, inst.liCookie); + log.logThreadLen = 0; + log.logThread[0] = String::EmptyChar; + log.logModuleId = 0; + log.logModuleLen = NEString::copyString(log.logModule, NETrace::LOG_NAMES_SIZE, inst.liName); + + _listInstances.add(inst); + NETrace::logAnyMessage(log); + + ASSERT(_mapScopes.contains(inst.liCookie) == false); + ::logObserverRequestScopes(inst.liCookie); + } + } +} + +void LogObserver::callbackDisconnecteInstances(const ITEM_ID * instances, uint32_t count) +{ + for (uint32_t i = 0; i < count; ++i) + { + const ITEM_ID& cookie = instances[i]; + for (uint32_t j = 0; j < _listInstances.getSize(); ++j) + { + const sLogInstance& inst{ _listInstances[j] }; + if (inst.liCookie == cookie) + { + NETrace::sLogMessage log{ }; + log.logDataType = NETrace::eLogDataType::LogDataLocal; + log.logMsgType = NETrace::eLogMessageType::LogMessageText; + log.logMessagePrio = NETrace::eLogPriority::PrioAny; + log.logSource = inst.liSource; + log.logTarget = NEService::COOKIE_LOCAL; + log.logCookie = inst.liCookie; + log.logModuleId = 0u; + log.logThreadId = 0u; + log.logTimestamp = static_cast(DateTime::getNow()); + log.logScopeId = 0u; + log.logMessageLen = String::formatString(log.logMessage, NETrace::LOG_MESSAGE_IZE, "DISCONNECTED the x%u instance %s with cookie %llu", inst.liBitness, inst.liName, inst.liCookie); + log.logThreadLen = 0; + log.logThread[0] = String::EmptyChar; + log.logModuleId = 0; + log.logModuleLen = NEString::copyString(log.logModule, NETrace::LOG_NAMES_SIZE, inst.liName); + + _listInstances.removeAt(j, 1); + _mapScopes.removeAt(cookie); + + NETrace::logAnyMessage(log); + break; + } + } + } +} + +void LogObserver::callbackLogScopes(ITEM_ID cookie, const sLogScope* scopes, uint32_t count) +{ + for (uint32_t i = 0; i < _listInstances.getSize(); ++i) + { + const sLogInstance& inst{ _listInstances[i] }; + if (cookie == inst.liCookie) + { + NETrace::sLogMessage log{ }; + log.logDataType = NETrace::eLogDataType::LogDataLocal; + log.logMsgType = NETrace::eLogMessageType::LogMessageText; + log.logMessagePrio = NETrace::eLogPriority::PrioAny; + log.logSource = inst.liSource; + log.logTarget = NEService::COOKIE_LOCAL; + log.logCookie = inst.liCookie; + log.logModuleId = 0u; + log.logThreadId = 0u; + log.logTimestamp = static_cast(DateTime::getNow()); + log.logScopeId = 0u; + log.logMessageLen = String::formatString(log.logMessage, NETrace::LOG_MESSAGE_IZE, "Registered %u scopes for instance %s with cookie %llu", count, inst.liName, inst.liCookie); + log.logThreadLen = 0; + log.logThread[0] = String::EmptyChar; + log.logModuleId = 0; + log.logModuleLen = NEString::copyString(log.logModule, NETrace::LOG_NAMES_SIZE, inst.liName); + + _mapScopes.setAt(cookie, ListScopes()); + ListScopes& scopeList{ _mapScopes.getAt(cookie) }; + scopeList.resize(count); + for (uint32_t j = 0; j < count; ++j) + { + scopeList[j] = scopes[j]; + } + + NETrace::logAnyMessage(log); + break; + } + } +} + +void LogObserver::callbackLogMessageEx(const unsigned char* logBuffer, uint32_t size) +{ + if (logBuffer != nullptr) + { + ASSERT(size >= sizeof(NETrace::sLogMessage)); + const NETrace::sLogMessage & log{ reinterpret_cast(*logBuffer)}; + NETrace::logAnyMessage(log); + } +} + +void LogObserver::logMain( int argc, char ** argv ) +{ + sObserverEvents evts + { + &LogObserver::callbackObserverConfigured + , &LogObserver::callbackServiceConnected + , &LogObserver::callbackObserverStarted + , &LogObserver::callbackMessagingFailed + , &LogObserver::callbackConnectedInstances + , &LogObserver::callbackDisconnecteInstances + , &LogObserver::callbackLogScopes + , nullptr + , &LogObserver::callbackLogMessageEx + }; + + ::logObserverInitialize(&evts, nullptr); + + _runConsoleInputExtended(); + + Application::signalAppQuit(); + ::logObserverDisconnectLogger(); + ::logObserverRelease(); +} + +bool LogObserver::_checkCommand(const String& cmd) +{ + OptionParser parser( LogObserver::ValidOptions, static_cast(MACRO_ARRAYLEN( LogObserver::ValidOptions )) ); + bool quit{ false }; + bool hasError {false}; + + LogObserver::_cleanHelp(); + + if ( parser.parseOptionLine( cmd ) ) + { + const OptionParser::InputOptionList & opts = parser.getOptions( ); + for ( uint32_t i = 0; i < opts.getSize( ); ++ i ) + { + const OptionParser::sOption & opt = opts[ i ]; + switch ( static_cast(opt.inCommand) ) + { + case eLoggerOptions::CMD_LogQueryScopes: + LogObserver::_processQueryScopes(opt); + break; + + case eLoggerOptions::CMD_LogSaveConfig: + LogObserver::_processSaveConfig(opt); + break; + + case eLoggerOptions::CMD_LogPrintHelp: + LogObserver::_processPrintHelp(); + break; + + case eLoggerOptions::CMD_LogInformation: + LogObserver::_processInfoInstances(); + break; + + case eLoggerOptions::CMD_LogUpdateScope: + LogObserver::_processUpdateScopes(opt); + break; + + case eLoggerOptions::CMD_LogPause: + LogObserver::_processPauseLogging(); + break; + + case eLoggerOptions::CMD_LogQuit: + quit = true; + break; + + case eLoggerOptions::CMD_LogRestart: + LogObserver::_processStartLogging(true); + break; + + case eLoggerOptions::CMD_LogStop: + LogObserver::_processStartLogging(false); + break; + + default: + hasError = true; + break; + } + } + } + else + { + hasError = true; + } + + Console & console = Console::getInstance( ); + console.lockConsole(); + if ( quit == false ) + { + if ( hasError ) + { + console.outputMsg( NESystemService::COORD_ERROR_MSG, NESystemService::FORMAT_MSG_ERROR.data( ), cmd.getString( ) ); + } + + console.clearLine( NESystemService::COORD_USER_INPUT ); + console.outputTxt( NESystemService::COORD_USER_INPUT, NESystemService::FORMAT_WAIT_QUIT ); + } + else + { + console.outputTxt( NESystemService::COORD_INFO_MSG, NESystemService::FORMAT_QUIT_APP ); + } + + console.refreshScreen( ); + console.unlockConsole( ); + + return quit; +} + +void LogObserver::_outputTitle( void ) +{ + Console & console = Console::getInstance( ); + console.lockConsole(); + console.outputTxt( NESystemService::COORD_TITLE, NELogObserverSettings::APP_TITLE.data( ) ); + console.outputTxt( NESystemService::COORD_SUBTITLE, NESystemService::MSG_SEPARATOR.data( ) ); + console.unlockConsole(); +} + +void LogObserver::_outputInfo( const String & info ) +{ + Console & console = Console::getInstance( ); + Console::Coord coord{NESystemService::COORD_INFO_MSG}; + console.lockConsole( ); + + console.outputTxt( coord, NESystemService::MSG_SEPARATOR.data( ) ); + ++ coord.posY; + console.outputStr( coord, info ); + + console.unlockConsole( ); +} + +void LogObserver::_cleanHelp(void) +{ + Console::Coord line{ NESystemService::COORD_INFO_MSG }; + Console& console = Console::getInstance(); + console.lockConsole(); + + console.clearLine(NESystemService::COORD_USER_INPUT); + uint32_t count = MACRO_ARRAYLEN(_msgHelp); + for (uint32_t i = 0; i < count; ++ i) + { + console.clearLine(line); + ++line.posY; + } + + console.unlockConsole(); +} + +void LogObserver::_processSaveConfig(const OptionParser::sOption& optSave) +{ + TEArrayList listTargets; + if (optSave.inString.empty() || (optSave.inString[0] == NEPersistence::SYNTAX_ALL_MODULES)) + { + listTargets.add(NEService::COOKIE_ANY); + } + else + { + for (const auto& elem : optSave.inString) + { + if (elem == NEPersistence::SYNTAX_ALL_MODULES) + { + listTargets.clear(); + listTargets.add(NEService::COOKIE_ANY); + break; + } + else if (elem.isNumeric()) + { + listTargets.add(elem.toUInt64()); + } + } + } + + for (const auto& target : listTargets.getData()) + { + ::logObserverRequestSaveConfig(target); + } +} + +void LogObserver::_processPrintHelp(void) +{ + Console::Coord line{ NESystemService::COORD_INFO_MSG }; + Console& console = Console::getInstance(); + console.lockConsole(); + for (const auto& text : _msgHelp) + { + console.outputTxt(line, text); + ++line.posY; + } + + console.unlockConsole(); +} + +void LogObserver::_processInfoInstances(void) +{ + static constexpr std::string_view _table{ " Nr. | Inst. ID | Bits | Scopes | Name " }; + static constexpr std::string_view _formt{ " %3u. |%11u | x%u | %5u | %s " }; + static constexpr std::string_view _empty{ "There are no connected instances ..." }; + + Console& console = Console::getInstance(); + Console::Coord coord{ NESystemService::COORD_INFO_MSG }; + console.lockConsole(); + + if (_listInstances.isEmpty()) + { + console.outputTxt(coord, NESystemService::MSG_SEPARATOR.data()); + ++coord.posY; + console.outputStr(coord, _empty); + ++coord.posY; + } + else + { + console.outputTxt(coord, NESystemService::MSG_SEPARATOR.data()); + ++coord.posY; + console.outputTxt(coord, _table); + ++coord.posY; + console.outputTxt(coord, NESystemService::MSG_SEPARATOR.data()); + ++coord.posY; + for (uint32_t i = 0; i < _listInstances.getSize(); ++ i) + { + const sLogInstance& instance{ _listInstances[i] }; + uint32_t id{ static_cast(instance.liCookie) }; + auto pos = _mapScopes.find(instance.liCookie); + uint32_t scopes{ pos != _mapScopes.invalidPosition() ? _mapScopes.valueAtPosition(pos).getSize() : 0u }; + console.outputMsg(coord, _formt.data(), (i + 1), id, static_cast(instance.liBitness), scopes, instance.liName); + ++coord.posY; + } + } + + console.outputTxt(coord, NESystemService::MSG_SEPARATOR.data()); + console.unlockConsole(); +} + +void LogObserver::_processUpdateScopes(const OptionParser::sOption& optScope) +{ + ASSERT(optScope.inCommand == static_cast(eLoggerOptions::CMD_LogUpdateScope)); + ASSERT(optScope.inString.empty() == false); + + const OptionParser::StrList& optValues{ optScope.inString }; + String scope; + for (const auto& entry : optValues) + { + if (entry == NEPersistence::SYNTAX_END_COMMAND) + { + LogObserver::_sendScopeUpdateMessage(scope); + scope.clear(); + } + else + { + scope += entry; + } + } + + if (scope.isEmpty() == false) + { + LogObserver::_sendScopeUpdateMessage(scope); + } +} + +void LogObserver::_processPauseLogging(void) +{ + ::logObserverPauseLogging(true); +} + +void LogObserver::_processStartLogging(bool doStart) +{ + if (doStart) + { + ASSERT(::logObserverIsInitialized()); + + if (::logObserverIsConnected() == false) + { + ::logObserverConnectLogger(nullptr, NESocket::InvalidPort); + } + else if (::logObserverIsStarted() == false) + { + ::logObserverPauseLogging(false); + } + } + else + { + ::logObserverDisconnectLogger(); + } +} + +void LogObserver::_processQueryScopes(const OptionParser::sOption& optScope) +{ + TEArrayList listTargets; + if (optScope.inString.empty() || (optScope.inString[0] == NEPersistence::SYNTAX_ALL_MODULES)) + { + listTargets.add(NEService::COOKIE_ANY); + } + else + { + for (const auto& elem : optScope.inString) + { + if (elem == NEPersistence::SYNTAX_ALL_MODULES) + { + listTargets.clear(); + listTargets.add(NEService::COOKIE_ANY); + break; + } + else if (elem.isNumeric()) + { + listTargets.add(elem.toUInt64()); + } + } + } + + for (const auto& target : listTargets.getData()) + { + ::logObserverRequestScopes(target); + } +} + +String LogObserver::_normalizeScopeProperty(const String & scope) +{ + const NEPersistence::sPropertyKey& propKey{ NEPersistence::DefaultPropertyKeys[static_cast(NEPersistence::eConfigKeys::EntryLogScope)] }; + String result; + if (scope.startsWith(propKey.property)) + { + result.append(propKey.section) + .append(NEPersistence::SYNTAX_OBJECT_SEPARATOR) + .append(NEPersistence::SYNTAX_ALL_MODULES) + .append(NEPersistence::SYNTAX_OBJECT_SEPARATOR) + .append(scope); + } + else + { + String prop(propKey.property); + prop += NEPersistence::SYNTAX_OBJECT_SEPARATOR; + NEString::CharPos pos = scope.findFirst(prop); + if ( scope.isValidPosition(pos)) + { + result.append(propKey.section) + .append(NEPersistence::SYNTAX_OBJECT_SEPARATOR) + .append(scope); + } + else + { + result = scope; + pos = result.findLast(NEPersistence::SYNTAX_OBJECT_SEPARATOR); + if (result.isValidPosition(pos)) + { + result.insertAt(prop, static_cast(pos + NEPersistence::SYNTAX_OBJECT_SEPARATOR.length())); + } + else + { + result.insertAt(prop, NEString::START_POS); + } + + result = _normalizeScopeProperty(result); + } + } + + return result; +} + +RemoteMessage LogObserver::_sendScopeUpdateMessage(const String& scope) +{ + RemoteMessage result; + + if (scope.isEmpty() == false) + { + Property prop(LogObserver::_normalizeScopeProperty(scope)); + if (prop.isValid() && prop.getPropertyType() == NEPersistence::eConfigKeys::EntryLogScope) + { + const PropertyKey& key{ prop.getKey() }; + ITEM_ID target{ key.isAllModules() ? NEService::COOKIE_ANY : key.getModule().toUInt32() }; + if (target >= NEService::COOKIE_ANY) + { + String scopeName{ key.getPosition() }; + uint32_t scopePrio{ prop.getValue().getIndetifier(NEApplication::LogScopePriorityIndentifiers) }; + sLogScope logScope; + logScope.lsId = NETrace::makeScopeIdEx(scopeName.getString()); + logScope.lsPrio = scopePrio; + NEString::copyString(logScope.lsName, LENGTH_SCOPE, scopeName.getString(), scopeName.getLength()); + ::logObserverRequestChangeScopePrio(target, &logScope, 1); + } + } + } + + return result; +} + +inline void LogObserver::enableLocalLogs(ConfigManager& config, bool enable) +{ + constexpr NEPersistence::eConfigKeys prioConfKey{ NEPersistence::eConfigKeys::EntryLogScope }; + const NEPersistence::sPropertyKey& keyPrio{ NEPersistence::getLogScope() }; + unsigned int prios = static_cast(NETrace::eLogPriority::PrioNotset); + const String prio{ NETrace::makePrioString(prios) }; + + config.setModuleProperty(keyPrio.section, keyPrio.property, String(NEPersistence::SYNTAX_ANY_VALUE), prio, prioConfKey, true); + config.setLogEnabled(NETrace::eLogingTypes::LogTypeRemote, false, true); +} diff --git a/framework/observer/app/private/Makefile b/framework/observer/app/private/Makefile new file mode 100644 index 000000000..793371aae --- /dev/null +++ b/framework/observer/app/private/Makefile @@ -0,0 +1,5 @@ +logobserver_SRC += \ + $(logobserver_BASE)/app/private/LogObserver.cpp \ + $(logobserver_BASE)/app/private/NELogObserverSettings.cpp \ + $(logobserver_BASE)/app/private/posix/LogObserverPosix.cpp \ + $(logobserver_BASE)/app/private/win32/LogObserverWin32.cpp \ diff --git a/framework/observer/app/private/NELogObserverSettings.cpp b/framework/observer/app/private/NELogObserverSettings.cpp new file mode 100644 index 000000000..838efdaea --- /dev/null +++ b/framework/observer/app/private/NELogObserverSettings.cpp @@ -0,0 +1,19 @@ +/************************************************************************ + * This file is part of the AREG SDK core engine. + * AREG SDK is dual-licensed under Free open source (Apache version 2.0 + * License) and Commercial (with various pricing models) licenses, depending + * on the nature of the project (commercial, research, academic or free). + * You should have received a copy of the AREG SDK license description in LICENSE.txt. + * If not, please contact to info[at]aregtech.com + * + * \copyright (c) 2017-2023 Aregtech UG. All rights reserved. + * \file observer/app/NELogObserverSettings.hpp + * \ingroup AREG SDK, Automated Real-time Event Grid Software Development Kit + * \author Artak Avetyan + * \brief AREG Platform, Log Observer console application, + * Log Observer Settings. + ************************************************************************/ +/************************************************************************ + * Include files. + ************************************************************************/ +#include "observer/app/NELogObserverSettings.hpp" diff --git a/framework/observer/app/private/posix/LogObserverPosix.cpp b/framework/observer/app/private/posix/LogObserverPosix.cpp new file mode 100644 index 000000000..fa34a365f --- /dev/null +++ b/framework/observer/app/private/posix/LogObserverPosix.cpp @@ -0,0 +1,42 @@ +/************************************************************************ + * This file is part of the AREG SDK core engine. + * AREG SDK is dual-licensed under Free open source (Apache version 2.0 + * License) and Commercial (with various pricing models) licenses, depending + * on the nature of the project (commercial, research, academic or free). + * You should have received a copy of the AREG SDK license description in LICENSE.txt. + * If not, please contact to info[at]aregtech.com + * + * \copyright (c) 2017-2023 Aregtech UG. All rights reserved. + * \file logger/private/app/LogObserverPosix.cpp + * \ingroup AREG SDK, Automated Real-time Event Grid Software Development Kit + * \author Artak Avetyan + * \brief Logger Observer, POSIX specific implementation + ************************************************************************/ + +/************************************************************************ + * Include files. + ************************************************************************/ +#include "observer/app/LogObserver.hpp" + +#ifdef _POSIX + +////////////////////////////////////////////////////////////////////////// +// Global functions, Begin +////////////////////////////////////////////////////////////////////////// + +int main(int argc, char* argv[], char* envp[]) +{ + LogObserver::getInstance().logMain(static_cast(argc), argv); + return 0; +} + +bool LogObserver::_osWaitUserInput(char* buffer, unsigned int bufSize) +{ +#if __STDC_WANT_LIB_EXT1__ + return(gets_s(buffer, bufSize) != nullptr); +#else // __STDC_WANT_LIB_EXT1__ + return (fgets(buffer, bufSize, stdin) != nullptr); +#endif // __STDC_WANT_LIB_EXT1__ +} + +#endif // _POSIX diff --git a/framework/observer/app/private/win32/LogObserverWin32.cpp b/framework/observer/app/private/win32/LogObserverWin32.cpp new file mode 100644 index 000000000..4273d5d53 --- /dev/null +++ b/framework/observer/app/private/win32/LogObserverWin32.cpp @@ -0,0 +1,90 @@ +/************************************************************************ + * This file is part of the AREG SDK core engine. + * AREG SDK is dual-licensed under Free open source (Apache version 2.0 + * License) and Commercial (with various pricing models) licenses, depending + * on the nature of the project (commercial, research, academic or free). + * You should have received a copy of the AREG SDK license description in LICENSE.txt. + * If not, please contact to info[at]aregtech.com + * + * \copyright (c) 2017-2023 Aregtech UG. All rights reserved. + * \file logger/app/private/LogObserverWin32.cpp + * \ingroup AREG SDK, Automated Real-time Event Grid Software Development Kit + * \author Artak Avetyan + * \brief LogObserver, Win32 specific implementation + ************************************************************************/ + +/************************************************************************ + * Include files. + ************************************************************************/ +#include "observer/app/LogObserver.hpp" + +#ifdef WINDOWS + +#pragma comment(lib, "areg.lib") +#pragma comment(lib, "observerapi.lib") +#pragma comment(lib, "areg-extend.lib") + +#ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN +#include +#include + +#include "observer/app/resources/resource.hpp" + +////////////////////////////////////////////////////////////////////////// +// Global functions, Begin +////////////////////////////////////////////////////////////////////////// + +namespace +{ + + inline char ** _convertArguments( TCHAR ** argv, int argc ) + { + char ** argvTemp = argc != 0 ? DEBUG_NEW char * [argc] : nullptr; + if ( argvTemp != nullptr ) + { + for ( int i = 0; i < static_cast(argc); ++i ) + { + TCHAR * entry = argv[i]; + uint32_t length = static_cast(NEString::getStringLength( entry )); + uint32_t size = length + 1u; + char * arg = DEBUG_NEW char[size]; + NEString::copyString( arg, size, entry ); + argvTemp[i] = arg; + } + } + return argvTemp; + } + + inline void _deleteArguments( char ** argv, int argc ) + { + if ( argv != nullptr ) + { + for ( int i = 0; i < static_cast(argc); ++i ) + delete[] argv[i]; + delete[] argv; + } + } + +} // namespace + +int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) +{ + char** argvTemp = _convertArguments(argv, static_cast(argc)); + LogObserver::getInstance().logMain(static_cast(argc), argvTemp); + _deleteArguments(argvTemp, static_cast(argc)); + + return 0; +} + +////////////////////////////////////////////////////////////////////////// +// Global functions, End +////////////////////////////////////////////////////////////////////////// + +bool LogObserver::_osWaitUserInput(char* buffer, unsigned int bufSize) +{ + return( gets_s(buffer, bufSize) != nullptr ); +} + +#endif // WINDOWS diff --git a/framework/observer/app/resources/RCa05912 b/framework/observer/app/resources/RCa05912 new file mode 100644 index 0000000000000000000000000000000000000000..0d4b3f3158dda4377f9f52ba8fc12d18c0a67d08 GIT binary patch literal 6604 zcmdU!+fE}#5QghIQr=-=ZW3j~VnbMxJC0r}UK`=VCK3|zV(cXWgFI&0NO|~tfA_R! z#va>P$%WC#^h|eEb)Boa*|IykwUOOeWMwPavHfb7JdZZE2m6!xYnxc?=6cNC*wB9B zyKjHFxdC%MyJ!9x_;E7(V4r}w;romGD~dg6J~|vxiGhA%{o1{2{f?O-kFd7gO3A*p zZ)_{ap=RFlMD_u`uYr4Tv<7e)S(mvOx;=0rWciUNax^8OIGr%|nVaPy0#DR#;c>$L zVIR+dG;|HkCvc^yQjXiVbJSuuoZVsDK06J}OZ9Ui=dBGK{Q*0Cw3;>S#G1Ud=JfC` znGrXGsr?S^9N4yXz^j3IWfyj8hmK0a>h=dSE&hJ6BUbAPU1@VOpR5hM&8x^eYe{+F z10EP*x6jTxZKVDkJxGJc$SHlCvR>ggZY**sLimxAAHrsRRU2tOU+iLzLX2SoNg@i5{mWWpA2J}<`h zLqUYZi3U@fS1g;cBKt0h7hgyE>~LsjM4-<bhV zFiwfM4j7WC&TNC(4r7&-XgcHJs(jbTYwzt1Yc1f87D8OHI-gl9cJN9pn_9R=ZF<0_ zVMb%tTX$`Dx)z}y4;_&e^Q>FPUF5#AeEMvB4~#q~2GesE^DRz9Rs0A?RPT6Hr~gh??-_li z7RNPwrH-#voo8GCx%jE!jZHjhF+_ePU+=dQNqja9d$*{ohj36|L3RDTW2&2%KEHF` z#@=sz1zV?nZD#%onL9g1)bygtzR2(QY|r_98H*HSMsEEGs#W}_;l4@*J%aDtE^Q~N zpvp<1`loqu&wMRZpRvw<>vkQNaCk{fc>gOA>+`k0MC2^)K}z7y(nvd!`L+Mjoy=1! z;Oyq-Qm>-u>2ZR*LnDh~`&|;-I`3S#*sbz*=<5Bc!^%gsvUH0Ip^pBXQKy48xmrC$ z(Nkj8pC;6YC_kvzNKdHhF8ujcRqiHWXU{)?layH!~W;B zcMk0)HtJxd_6y(xg=hfE6!M_Vlhk_Y`03fRp7grQ`9-Q|ueO zT{kAnpm#FR+0$d-vI&2l?jGFf*-J12M4Qw9Ih^Hp539ak&clQ~^USXC0|^T48RSD8E9f%zPv8wz#H>T=b~ z`nxsXeGh?+&{(+3xTl-G177!0f{Ylo=I_fyH(n}JKK6nvW%}ivn8PtKIA^T@ijA+@Zsil^(H=vicA^Or{o^U(u=b*qsV1@K+(OifA_zTB;J_E!a4cy4Yh^DVcRDGT(Yf-4{2}Eceaq(SGSI%yUEHz!KX(qBS?9!+^pw|01#SA- z^=}Y2Th1V_#)wR+b3*_N=+wHsYe$U#6ePmShD&p^B>2uySylbs@uYIPy&-w#c zpc-6UYC)x+ErDgUwQ8BlZ7hIURRB*7exZ#T}AXG2* z=^weGTI5~Inq#r?3QZRh5>Vvy7AqDy*^i;1p6BY7;LQSXZ{;g>M z?fm5AM!1uJ~14CP5-;mbWJGeF0 z_iurN!(6GBI54yo4h(CB{j~e(6Em$hj*V=Fqpvo{5$e#07L+U2`wvFkn8s8S#Efo= z^|!}o{tozLT1|Z7UlaSMxZ(5FgK^Rilm(Khv|vko7i5X}36?lI))Ggklas69 zVxSe$=33+10BfA^v%)uXY;b;dHGCaV4e6oPadwt1PEE7L#SjO4G`kKy33kG#^P1yK zcx(J^Ra<Ti+?95-JJvGIWK0JnTs;vs^DcXy)=jK$w z=lme~e0CM~SM61i7E+Zy6!Vv8(?YCpX|5H%3$bS21{dbq;8I96Tne>C8jm-9o*mM| z?2r~#1K&~U^BwT@ygK+I#1UDG8sIO%&iE*}A+E1$jbGNa!S(fRas9ovxba>)TBY{5 zxxo`Rq9|oIDtY0?rjE#1t!!u9+}s5>w|2#i&D55z%y+}h?JrQ>af9~O4zA^n9=Nr$ z7jEt9gPXg&@$23JxV49(y|Q~4emOiI-)H_6dH=qKoBYhlq5e+&PW_AegZf|U-_)N} z9@RJC3MS7vp?yXL1qC4>AOQaU{+Kjr5++WZhzS!Wz}MFoW5Wxo&I+1!G$zZHn#$;`!98-<yjHIyy#~ zd!^|5sm6LSF)_!K%8;V#rWzZU(N_%@(#Q5Ewg{KRHI95 zY?=LIo2D9@#Ky*zb^O>SmHu~IE44l?Dgh-;K81z)WLJ`;4wqn z_ZrZ%LmzL?wy3kD_lL%jZ@l`n*YIJJ=8o?=KVm^dc=tK8XTNSrUK1xwofb5!|4WPJ z4;&O=5uecStt8`&$o&U)@7lX>*XEsj-g|fBj_upFZrx%^n^vq{{r0M5OP8-%`Odni z4ek1_pUw~WS3(xf3w~KkBmDdVRSL~dfr0)bOf7sI@n%@?lm1=c0pd4Z&T02Hm@RH2 z)we;5{I7(S*0d0%twR;wLsA|##n-X4buN70s`TsBg@MbpxknH6!QPjfV-K~P+VA6v z_lLE?{$Xwi?eB?&gE}IlpC>|?5A<%2&;edpIl33d4IhkA?7Qcs#@NdnYWsbf({dao zjuAS*69M!eGt37G)4CyX#*2ub-V>ij1>vuo!mzs+z)KgL@b7{zHqOE48v-$!zJ3#Y zv6uJbc6$T6dQ*KU=65px!K_Y5n$a2Cr*_9zn`Ys&O+gqt+y{pT0q+l>1_JwOKM87w zj|1D|zXCjwI@=4Ewok|DRTFSw+Z#B)bq3CDnTav%mol33yacQq;D9qB?)YqOTV(8< zhO{02IO`82u>Hs|UYpK$#ksIn_%f8&v3sW=YtK}ip9y^Z1~r3H`B~I#;2iDQ=@jeE zsP;Kl_%^%|E=9QF`(^IPTIr6TH*`S`ui5^ww+}9?dJfr}dg8{OA;>xEhiiu?LYUzwb+T)8Ci=PAZtkjWKvm68X{|HBivlm3|Y&X;^sP6+GhB5eJk92w>5I2 z+$j(Ix}hC1827D>9dK(?2jp()h@8zG@!QT$$l2N%x3+e|?QJ|JOre?J8PhnJ%Ni~CLrzWB&44|iS%zyB8@if zn`DaR3m@|O^QyPhwX#dzrgIKY+OQIBHLeiIw|EP z&VT0+jvL~&)rdRJe}-vnAIJ6*Q-ZDH1N-*w-gRv2&ZLw99b3D3xO=#{xw*T!wQ+Oz@bGBcd0?|n&$#sN_2S8-lrFX#RqEa{~iIg60Iwp0)kazxeJo zgX#N&>G3k(9Zpk`k46?8yGp_NR9<~gx%0b2>EBc6h6N*s;*a0{2Wy6O#7ZA8q(u55 zXmAg#9`ZC+QBk9x#nSQpa4CKpR!sCp#>stnXRBl-)qQFW^fsryy=(Z?FI2AS<5;lV$HB*W zpm$$$hhFu3THa~z+qYL;AE$u>2QZl)2G;Ru)3f^vUAny3rOUHDp6~jct50i}CXE|6 zZPK7&qvp+?vT*b1+^M5y`wmZgdAPT0`%H^xiXL6DvWOu*60xx;u6V#Q2{0r8adCy( zEn;IuV&g28p4jI>W#CW53OF&!CsAr~RottogHM>&s@S>DKq|7h|3SD9 zqF9XiYwfgmNUJRFhY%(1o6xLY)@?;QKJMM%9Zv1};>0~2!r#}0zp0zW`xNH9UeDj( zg}=XRQtjm}{_d~Eq+;bB6m$ICmr^L!lH$^jp`^CQQOEr>=J>f^rrg)^KRssd^D)QI zeLuo|80KTp^Sb>{=X%)v)pLRSmCW&T|B@EJinpT1Tyzb%m&zPJ_g4w`z?hFg`Rd1_ z>Wj7&9jm;{DmLy1Gsn+8Vp@!PtSTNouWWh8cdz+W{M_4Sj-PwjDs;R>k4LR3_uiS~ z=YBll{weJklr8FC(aI`*?jJPA&pn00ytW2@1pNNmFr)z)}MRaMZIsT^P*Jr zd{v~ficiI=V%Fb3xlf-prc}}2|5bcSDrP-?@&@_Qn~c8Rs-)*Df-M*%`H0H+%lZ72 zvi{EGQOr#h;dxS84CWx2AwMJBn{b$~fyU%&3N}@!=X}9qDHtRuG5tUm68j-~fkG1sqOUyGmYlwPgb z2OYaS`ssnHnDzL{f$7y1HvU2ZvOsRl96y=1qRkb)O#V)fzZuy)A>;K#iJYK%{YIx)`7mahDM1B1t%cm9kaZNYkD4X_DC9qd+$8->B5TQhB} zPLpFP(T5^y$$V8IA1dTRh5V#84>?gGBg(O=3b|S#mnh^Cg)FI%vsB;THmdl^aSGW> zA@3;U9fcgEkcSj)tKX)y|CMyJ9 zWMGAisgNZVGNwZIRLI7bES?uKuA0cIN->306SAtME58p}SdPK5N}H!(y?QQ$SPR)# zEw=cH;9p8myVEOE~ZJrY}3iIg?0rP&%LTBp=}8h@I%TXv<9-xUO`%}-uWt5a*E=2Z6^)Nip$4?6}mrb=W3r9pMm{N(?%I<=0f{ZX!iK0oKQ1d^EdG#^%`N>O4Lp#&)lc_BC`N?cbBh&ou z$Ha>#mE4>Z3XbJ2L!+Nt++W%XmzCnEDKwe#1XEVN#&9kX7z*Ba>aDt~p(O7d58 ztNMbLMIj4qo}V1Gs?t)?V|bWl{j*<9L>}8bKN)V*HyMT)&Xn7jpKpqbGz6zmVk@{(S%;moMb= zg`B=PIy$QPUCF}>xq2agFXZoq+`W*w*DN`FAuBIr%G&-D!IW`F9}` zFJ#_@jJ%MQmz-@~sV+i3UdYL7B1xFE+kg*rC_sn}}eaYVo*?J*YFZ>$;!oOJ{ z{QCgB-)1FF4i?imzkPZz{4Rvr{h7I>sgUu{%LsSK%b0JUml0-1RnN;GSP!(-+jpO%JopO`B((dnpK-(&yRaUJ6F; zchnE_k$Wv1f4{oG;*T$8Vx5|ss!Wf01@yO_$nuNBLZ4Gvb)Vu6x9f7RD3t3{RPFna z@~=**zWfUs8kYPPZCSL4e)B1xT|TXnSM+U>y|{O?8%m4vtzIr_BVKg5vCP}`*3dR} z&a!{N#n>%>kU18z!$Q_q$meQ#RW3=oZ=knFmg=8&V&`qOUg~p1N&lWwnpHmPb9YW3 zw+z)kIP(xwOMAJX5{|A*v__uZdtvV;w2rOkgeCCc1i z#a5Q%Amc3IgIa3+fBIm(x&OWTs_~Un|HxNN{coH$#m{POUDev^Dy>e{FMhe1Y5iiu zZCRn{mk3i=Ms7dtz)^tG4v7+LBgc==?Srftqlho>YrN4t+KH{$rjbQ$fLJ~Nxl z9hwVMr&sIRre*%1C*k*_Ii;tSQj%2rdF6F34kOb*-c`$u(D2keFuFvG(nAlaf9F>^ zt0AZKQK$cyd)3bCmL0K!(`%7NMRS1meuLs!sW&XK{@nW6GWCbh!UtB48*5`{?dL4{ z0cp;x9PL6Y7Ww2S>lrs_=P!Iy960|vz;8Fn_}pIJF8k{>&q?@_xY&OwT};%mn@curTrA7n{ z@yHgJ=>E$Um9FeTbL*H8DB~M%G6oqF7dyjmI{og;+v4Wrm16Bb0lz8F0qamBle( zn-F52&Rw!Hve`$tsB9Q9Q%EHby0)HjZ@G!=d!8?sJs+4O&seb1@x9<(oG3SoAFUD9 zF_&=kpLFzr*5zAq+{71J_)>%W6wB4|kAeM-SQTDPyiFJu_LjfJ>^vnZR#EvdmC5Bn z&qV?vp1@1%8T#9Eu>hBx9>Sev-4Nl|v3nh9ek7kR#$fN&YIRr9c=620j-TQW4Lqf7 z-@Lu!0u*=k)1^5|F-}>=;j{J;^6#>bv(YB346SqtXP0=t^RJBGB6N<4mGUYfhE5qR z#hI%e%IADbJyA||z3z>vNYxuw8JoD@z4j>MtIXx$FQnEWqUJjUr+r;!UAzYU&FEPB^BM7A<=0xn2zU0T)fJ@T@u_o6Fi z)Ybf|E|e=GW-IgSj5p`4vvMxWFl%Z#E)i5`Co$aUnJ$Js< znOd3^=I3hzjq4s*`#Bs>u%1wRXg%PZXRQ{_`w?YN^=oCsQ`6cyoD+c(Z^-NJuBLOl zQ0ZWmK6dG?P%U2Jsh_ils!fOb2`9M->VKQJ)JZK%Jw#^JxOF_Y&zg|WjFO{JeOiBu zZ|Q5m=J`jt`97nED>`uLXupF;UGLI0nYMbI=({#TB!%Z88+TQ6ILq%`jIXM(JLpxK ziQyoN^>eJQIByd9BkUhWNij7aw;@$Ya%A3Hi9YiiQp(m8;lCgC?Z8%VeXD~QzV$U= zMoyYgdA4aE;5fD?h?tqGdGCwxc-J<2cG5kBXxiE9Pj7keDLYl%5_$457rovlVH;Yg%Z^j3rboPR zxu!>lW;*e1_MP2#+}$%W^z!np_k^)NK#TJyo$iu5Lf!SCrs!T^DSg?1KxXqq4US7q0pD!%?iSPMpO_N=+wHsYe$U#6ePmShD&p^B>2uySylbs@uYIPy&-w#c zpc-6UYC)x+ErDgUwQ8BlZ7hIURRB*7exZ#T}AXG2* z=^weGTI5~Inq#r?3QZRh5>Vvy7AqDy*^i;1p6BY7;LQSXZ{;g>M z?fm5AM!1uJ~14CP5-;mbWJGeF0 z_iurN!(6GBI54yo4h(CB{j~e(6Em$hj*V=Fqpvo{5$e#07L+U2`wvFkn8s8S#Efo= z^|!}o{tozLT1|Z7UlaSMxZ(5FgK^Rilm(Khv|vko7i5X}36?lI))Ggklas69 zVxSe$=33+10BfA^v%)uXY;b;dHGCaV4e6oPadwt1PEE7L#SjO4G`kKy33kG#^P1yK zcx(J^Ra<Ti+?95-JJvGIWK0JnTs;vs^DcXy)=jK$w z=lme~e0CM~SM61i7E+Zy6!Vv8(?YCpX|5H%3$bS21{dbq;8I96Tne>C8jm-9o*mM| z?2r~#1K&~U^BwT@ygK+I#1UDG8sIO%&iE*}A+E1$jbGNa!S(fRas9ovxba>)TBY{5 zxxo`Rq9|oIDtY0?rjE#1t!!u9+}s5>w|2#i&D55z%y+}h?JrQ>af9~O4zA^n9=Nr$ z7jEt9gPXg&@$23JxV49(y|Q~4emOiI-)H_6dH=qKoBYhlq5e+&PW_AegZf|U-_)N} z9@RJC3MS7vp?yXL1qC4>AOQaU{+Kjr5++WZhzS!Wz}MFoW5Wxo&I+1!G$zZHn#$;`!98-<yjHIyy#~ zd!^|5sm6LSF)_!K%8;V#rWzZU(N_%@(#Q5Ewg{KRHI95 zY?=LIo2D9@#Ky*zb^O>SmHu~IE44l?Dgh-;K81z)WLJ`;4wqn z_ZrZ%LmzL?wy3kD_lL%jZ@l`n*YIJJ=8o?=KVm^dc=tK8XTNSrUK1xwofb5!|4WPJ z4;&O=5uecStt8`&$o&U)@7lX>*XEsj-g|fBj_upFZrx%^n^vq{{r0M5OP8-%`Odni z4ek1_pUw~WS3(xf3w~KkBmDdVRSL~dfr0)bOf7sI@n%@?lm1=c0pd4Z&T02Hm@RH2 z)we;5{I7(S*0d0%twR;wLsA|##n-X4buN70s`TsBg@MbpxknH6!QPjfV-K~P+VA6v z_lLE?{$Xwi?eB?&gE}IlpC>|?5A<%2&;edpIl33d4IhkA?7Qcs#@NdnYWsbf({dao zjuAS*69M!eGt37G)4CyX#*2ub-V>ij1>vuo!mzs+z)KgL@b7{zHqOE48v-$!zJ3#Y zv6uJbc6$T6dQ*KU=65px!K_Y5n$a2Cr*_9zn`Ys&O+gqt+y{pT0q+l>1_JwOKM87w zj|1D|zXCjwI@=4Ewok|DRTFSw+Z#B)bq3CDnTav%mol33yacQq;D9qB?)YqOTV(8< zhO{02IO`82u>Hs|UYpK$#ksIn_%f8&v3sW=YtK}ip9y^Z1~r3H`B~I#;2iDQ=@jeE zsP;Kl_%^%|E=9QF`(^IPTIr6TH*`S`ui5^ww+}9?dJfr}dg8{OA;>xEhiiu?LYUzwb+T)8Ci=PAZtkjWKvm68X{|HBivlm3|Y&X;^sP6+GhB5eJk92w>5I2 z+$j(Ix}hC1827D>9dK(?2jp()h@8zG@!QT$$l2N%x3+e|?QJ|JOre?J8PhnJ%Ni~CLrzWB&44|iS%zyB8@if zn`DaR3m@|O^QyPhwX#dzrgIKY+OQIBHLeiIw|EP z&VT0+jvL~&)rdRJe}-vnAIJ6*Q-ZDH1N-*w-gRv2&ZLw99b3D3xO=#{xw*T!wQ+Oz@bGBcd0?|n&$#sN_2S8-lrFX#RqEa{~iIg60Iwp0)kazxeJo zgX#N&>G3k(9Zpk`k46?8yGp_NR9<~gx%0b2>EBc6h6N*s;*a0{2Wy6O#7ZA8q(u55 zXmAg#9`ZC+QBk9x#nSQpa4CKpR!sCp#>stnXRBl-)qQFW^fsryy=(Z?FI2AS<5;lV$HB*W zpm$$$hhFu3THa~z+qYL;AE$u>2QZl)2G;Ru)3f^vUAny3rOUHDp6~jct50i}CXE|6 zZPK7&qvp+?vT*b1+^M5y`wmZgdAPT0`%H^xiXL6DvWOu*60xx;u6V#Q2{0r8adCy( zEn;IuV&g28p4jI>W#CW53OF&!CsAr~RottogHM>&s@S>DKq|7h|3SD9 zqF9XiYwfgmNUJRFhY%(1o6xLY)@?;QKJMM%9Zv1};>0~2!r#}0zp0zW`xNH9UeDj( zg}=XRQtjm}{_d~Eq+;bB6m$ICmr^L!lH$^jp`^CQQOEr>=J>f^rrg)^KRssd^D)QI zeLuo|80KTp^Sb>{=X%)v)pLRSmCW&T|B@EJinpT1Tyzb%m&zPJ_g4w`z?hFg`Rd1_ z>Wj7&9jm;{DmLy1Gsn+8Vp@!PtSTNouWWh8cdz+W{M_4Sj-PwjDs;R>k4LR3_uiS~ z=YBll{weJklr8FC(aI`*?jJPA&pn00ytW2@1pNNmFr)z)}MRaMZIsT^P*Jr zd{v~ficiI=V%Fb3xlf-prc}}2|5bcSDrP-?@&@_Qn~c8Rs-)*Df-M*%`H0H+%lZ72 zvi{EGQOr#h;dxS84CWx2AwMJBn{b$~fyU%&3N}@!=X}9qDHtRuG5tUm68j-~fkG1sqOUyGmYlwPgb z2OYaS`ssnHnDzL{f$7y1HvU2ZvOsRl96y=1qRkb)O#V)fzZuy)A>;K#iJYK%{YIx)`7mahDM1B1t%cm9kaZNYkD4X_DC9qd+$8->B5TQhB} zPLpFP(T5^y$$V8IA1dTRh5V#84>?gGBg(O=3b|S#mnh^Cg)FI%vsB;THmdl^aSGW> zA@3;U9fcgEkcSj)tKX)y|CMyJ9 zWMGAisgNZVGNwZIRLI7bES?uKuA0cIN->306SAtME58p}SdPK5N}H!(y?QQ$SPR)# zEw=cH;9p8myVEOE~ZJrY}3iIg?0rP&%LTBp=}8h@I%TXv<9-xUO`%}-uWt5a*E=2Z6^)Nip$4?6}mrb=W3r9pMm{N(?%I<=0f{ZX!iK0oKQ1d^EdG#^%`N>O4Lp#&)lc_BC`N?cbBh&ou z$Ha>#mE4>Z3XbJ2L!+Nt++W%XmzCnEDKwe#1XEVN#&9kX7z*Ba>aDt~p(O7d58 ztNMbLMIj4qo}V1Gs?t)?V|bWl{j*<9L>}8bKN)V*HyMT)&Xn7jpKpqbGz6zmVk@{(S%;moMb= zg`B=PIy$QPUCF}>xq2agFXZoq+`W*w*DN`FAuBIr%G&-D!IW`F9}` zFJ#_@jJ%MQmz-@~sV+i3UdYL7B1xFE+kg*rC_sn}}eaYVo*?J*YFZ>$;!oOJ{ z{QCgB-)1FF4i?imzkPZz{4Rvr{h7I>sgUu{%LsSK%b0JUml0-1RnN;GSP!(-+jpO%JopO`B((dnpK-(&yRaUJ6F; zchnE_k$Wv1f4{oG;*T$8Vx5|ss!Wf01@yO_$nuNBLZ4Gvb)Vu6x9f7RD3t3{RPFna z@~=**zWfUs8kYPPZCSL4e)B1xT|TXnSM+U>y|{O?8%m4vtzIr_BVKg5vCP}`*3dR} z&a!{N#n>%>kU18z!$Q_q$meQ#RW3=oZ=knFmg=8&V&`qOUg~p1N&lWwnpHmPb9YW3 zw+z)kIP(xwOMAJX5{|A*v__uZdtvV;w2rOkgeCCc1i z#a5Q%Amc3IgIa3+fBIm(x&OWTs_~Un|HxNN{coH$#m{POUDev^Dy>e{FMhe1Y5iiu zZ + +#endif // _WINDOWS + +#endif // AREG_LOGGER_RESOUR_TARGETVER_HPP diff --git a/framework/observer/lib/LogObserverApi.h b/framework/observer/lib/LogObserverApi.h index 83a1d147f..895ff2825 100644 --- a/framework/observer/lib/LogObserverApi.h +++ b/framework/observer/lib/LogObserverApi.h @@ -16,6 +16,9 @@ * ************************************************************************/ +/************************************************************************ + * Include files. + ************************************************************************/ #include "observer/lib/LogObserverSwitches.h" /** @@ -62,15 +65,17 @@ struct sLogInstance { /* The type of the message source application. Either client, test or simulation */ - unsigned int liSource; + uint32_t liSource; /* The bitness of the application, should be either 32 or 64 */ - unsigned int liBitness; + uint32_t liBitness; /* The cookie ID of the connected client. */ - unsigned long long liCookie; + ITEM_ID liCookie; + /* The connection timestamp */ + TIME64 liTimestamp; /* The name of the connected application */ - char liName[LENGTH_NAME]; + char liName[LENGTH_NAME]; /* The name of the file location. */ - char liLocation[LENGTH_LOCATION]; + char liLocation[LENGTH_LOCATION]; }; /** @@ -115,11 +120,11 @@ enum eLogPriority struct sLogScope { /* The ID of the scope. Can be 0 if unknown or if indicates to scope group. */ - unsigned int lsId; + uint32_t lsId; /* The priority of the scope to log messages. These are values of eLogPriority. Can be set bitwise. */ - unsigned int lsPrio; + uint32_t lsPrio; /* The name of the scope or scope group. The scope groups are ending with '*'. For example 'areg_base_*' */ - char lsName[LENGTH_SCOPE]; + char lsName[LENGTH_SCOPE]; }; /** @@ -128,36 +133,68 @@ struct sLogScope struct sLogMessage { /* The type of the message: scope enter, scope exit or message text. */ - eLogType msgType; + eLogType msgType; /* The priority of the message to log. */ - eLogPriority msgPriority; + eLogPriority msgPriority; /* The ID of the message source. This value is indicated in the sLogInstance::liCookie */ - unsigned long long msgSource; + ITEM_ID msgSource; /* The cookie ID of the message. This value is indicated in the sLogInstance::liCookie */ - unsigned long long msgCookie; + ITEM_ID msgCookie; /* The ID of the process, running on the local machine. */ - unsigned long long msgModuleId; + ITEM_ID msgModuleId; /* The ID of the thread where the log has been generated. */ - unsigned long long msgThreadId; + ITEM_ID msgThreadId; /* The timestamp where the log was generated. */ - unsigned long long msgTimestamp; + TIME64 msgTimestamp; /* The ID of the scope that generated message. Same as indicated in sLogScope::lsId. */ - unsigned int msgScopeId; + uint32_t msgScopeId; /* The text of generated log message. */ - char msgLogText[LENGTH_MESSAGE]; + char msgLogText[LENGTH_MESSAGE]; /* The name of the thread, if set, where the message was generated. */ - char msgThread[LENGTH_NAME]; + char msgThread[LENGTH_NAME]; /* The name of the application that generated the message. Same as in sLogInstance::liName */ - char msgModule[LENGTH_NAME]; + char msgModule[LENGTH_NAME]; +}; + +/** + * \brief The states of the log observer. + **/ +enum eObserverStates +{ + /* The lob observer is uninitialized */ + ObserverUninitialized = 0 + /* The log observer is initialized, but disconnected / stopped. */ + , ObserverDisconnected = 1 + /* The log observer is connected and started. */ + , ObserverConnected = 3 + /* The log observer is connected, but paused, i.e. receives, but does not write or forward logs. */ + , ObserverPaused = 7 }; +/** + * \brief The callback of the event triggered when initializing and configuring the observer. + * The callback indicates the IP address and port number of the logger service set + * in the configuration file. + * \param address The null-terminated string of the IP address of the logger service set in the configuration file. + * \param port The IP port number of the logger service set in the configuration file. + **/ +typedef void (*FuncObserverConfigured)(const char * /*address*/, uint16_t /*port*/); + /** * \brief The callback of the event triggered when the observer connects or disconnects from the logger service. * \param isConnected Flag, indicating whether observer is connected or disconnected. * \param address The IP address of the logger service to connect or disconnect. * \param port The IP port number of the logger service to connect or disconnect. **/ -typedef void (*FuncServiceConnected)(bool /*isConnected*/, const char * /*address*/, unsigned short /*port*/); +typedef void (*FuncServiceConnected)(bool /*isConnected*/, const char * /*address*/, uint16_t /*port*/); + +/** + * \brief The callback of the event trigger when starting or pausing the log observer. + * If the log observer is paused, on start it continues to write logs in the same file. + * If the log observer is stopped (disconnected is called), on start it creates new file. + * \param isStarted The flag indicating whether the lob observer is started or paused. + **/ +typedef void(*FuncObserverStarted)(bool /*isStarted*/); /** * \brief The callback of the event triggered when fails to send or receive message. @@ -165,11 +202,18 @@ typedef void (*FuncServiceConnected)(bool /*isConnected*/, const char * /*addres typedef void (*FuncMessagingFailed)(); /** - * \brief The callback of the event triggered when receive the list of connected instances that log messages. - * \param instances The pointer to the list of instances. + * \brief The callback of the event triggered when receive the list of connected instances that make logs. + * \param instances The pointer to the list of the connected instances. * \param count The number of entries in the list. **/ -typedef void (*FuncLogInstances)(sLogInstance* /*instances*/, unsigned int /*count*/); +typedef void (*FuncInstancesConnect)(const sLogInstance* /*instances*/, uint32_t /*count*/); + +/** + * \brief The callback of the event triggered when receive the list of disconnected instances that make logs. + * \param instances The pointer to the list of IDs of the disconnected instances. + * \param count The number of entries in the list. + **/ +typedef void (*FuncInstancesDisconnect)(const ITEM_ID * /*instances*/, uint32_t /*count*/); /** * \brief The callback of the event triggered when receive the list of the scopes registered in an application. @@ -177,7 +221,7 @@ typedef void (*FuncLogInstances)(sLogInstance* /*instances*/, unsigned int /*cou * \param scopes The list of the scopes registered in the application. Each entry contains the ID of the scope, message priority and the full name. * \param count The number of scope entries in the list. **/ -typedef void (*FuncLogScopes)(unsigned long long /*cookie*/, sLogScope* /*scopes*/, unsigned int /*count*/); +typedef void (*FuncLogScopes)(ITEM_ID /*cookie*/, const sLogScope* /*scopes*/, uint32_t /*count*/); /** * \brief The callback of the event triggered when receive message to log. @@ -185,21 +229,37 @@ typedef void (*FuncLogScopes)(unsigned long long /*cookie*/, sLogScope* /*scopes **/ typedef void (*FuncLogMessage)(const sLogMessage * /*logMessage*/); +/** + * \brief The callback of the event triggered when receive remote message to log. + * The buffer indicates to the NETrace::sLogMessage structure. + * \param logBuffer The pointer to the NETrace::sLogMessage structure to log messages. + * \param size The size of the buffer with log message. + **/ +typedef void (*FuncLogMessageEx)(const unsigned char* /*logBuffer*/, uint32_t /*size*/); + /** * \brief The structure of the callbacks / events to set when send or receive messages. **/ struct sObserverEvents { + /* The callback to the trigger when the observer is initialized and configured. */ + FuncObserverConfigured evtObserverConfigured; /* The callback to trigger when connect or disconnect logger service. */ FuncServiceConnected evtServiceConnected; + /* The callback to trigger when log observer is tarted or paused. */ + FuncObserverStarted evtLoggingStarted; /* The callback to trigger when fails to send or receive message. */ FuncMessagingFailed evtMessagingFailed; - /* The callback to trigger when receive list of connected instances that log messages. */ - FuncLogInstances evtLogSources; + /* The callback to trigger when receive list of connected instances that make logs. */ + FuncInstancesConnect evtInstConnected; + /* The callback to trigger when receive list of IDs of the disconnected instances that make logs. */ + FuncInstancesDisconnect evtInstDisconnected; /* The callback to trigger when receive list of registered scopes. */ FuncLogScopes evtLogScopes; - /* The callback to trigger when receive a message to log. */ + /* The callback to trigger when receive a message to log. If is set and not null, the 'evtLogMessageEx' callback is ignored. */ FuncLogMessage evtLogMessage; + /* The callback to trigger when receive remote message to log. To use, set the 'evtLogMessage' callback null. */ + FuncLogMessageEx evtLogMessageEx; }; /** @@ -210,7 +270,7 @@ struct sObserverEvents * If NULL, it uses the default location of the config file './config/areg.init' * \returns Returns true, if succeeded to initialize internals. Otherwise, returns false. **/ -OBSERVER_API bool logObserverInitialize(const sObserverEvents * callbacks, const char * configFilePath); +OBSERVER_API bool logObserverInitialize(const sObserverEvents * callbacks, const char * configFilePath = 0); /** * \brief Call to release the log observer internals and release resources. This function should @@ -231,7 +291,7 @@ OBSERVER_API void logObserverRelease(); * \note The 'ipAddress' and 'portNr' parameters should be either both valid or they are ignored and the default values * indicated in the configuration file are used. **/ -OBSERVER_API bool logObserverConnectLogger(const char* ipAddress, unsigned short portNr); +OBSERVER_API bool logObserverConnectLogger(const char* ipAddress = 0, uint16_t portNr = 0); /** * \brief Call to trigger disconnect from logger service. @@ -239,6 +299,19 @@ OBSERVER_API bool logObserverConnectLogger(const char* ipAddress, unsigned short **/ OBSERVER_API void logObserverDisconnectLogger(); +/** + * \brief Call to start paused log observer. By default, when log observer is connected, it is in started state. + * When call logObserverStart(false) it pauses the log observer and no messages are logged. + * On start, the log observer resumes and continues writing logs. + * \param doPause The flag to set to indicate whether the log observer should pause or resume writing logs. + **/ +OBSERVER_API void logObserverPauseLogging(bool doPause); + +/** + * \brief Call to get the current state of the log observer. + **/ +OBSERVER_API eObserverStates logObserverCurrentState(); + /** * \brief Returns true if observer is initialized and the logger service connection is triggered. * Otherwise, it returns false. @@ -252,6 +325,12 @@ OBSERVER_API bool logObserverIsInitialized(); **/ OBSERVER_API bool logObserverIsConnected(); +/** + * \brief Returns true, if log observer is initialized, connected, receives and writes or forwards logs. + * In all other cases it returns false. + **/ +OBSERVER_API bool logObserverIsStarted(); + /** * \brief Returns the current IP address of the logger service to connect. * Returns empty string, if not configured or the IP address is unknown @@ -262,7 +341,7 @@ OBSERVER_API const char * logObserverLoggerAddress(); * \brief Returns the current IP port of the logger service to connect. * Return 0 (invalid port), if not configured or the port number is unknown **/ -OBSERVER_API unsigned short logObserverLoggerPort(); +OBSERVER_API uint16_t logObserverLoggerPort(); /** * \brief Return true if logger TCP/IP connection is enabled in the configuration file. @@ -273,11 +352,11 @@ OBSERVER_API bool logObserverConfigLoggerEnabled(); /** * \brief On exit, the addrBuffer contains the IP address of the logger registered in the configuration file. * \param addrBuffer Should be valid pointer of the buffer to write the IP address, the minimum size should be 16 bytes. - * \param count The length of the buffer to write the IP address, inclusive the null-terminated character at the end. + * \param space The length of the buffer to write the IP address, inclusive the null-terminated character at the end. * \return Returns true, if succeeds to write the address. Returns false, if the observer is not configured, * or the address is not specified in the configuration, or the buffer is not big enough to write address. **/ -OBSERVER_API bool logObserverConfigLoggerAddress(char * addrBuffer, int count); +OBSERVER_API bool logObserverConfigLoggerAddress(char * addrBuffer, uint32_t space); /** * \brief Returns the configured IP port of the logger service to connect, @@ -298,7 +377,7 @@ OBSERVER_API void logObserverRequestInstances(); * If the target is ID_IGNORE (or 0), it receives the list of scopes of all connected instances. * Otherwise, should be indicated the valid cookie ID of the connected log instance. **/ -OBSERVER_API void logObserverRequestScopes(unsigned long long target); +OBSERVER_API void logObserverRequestScopes(ITEM_ID target); /** * \brief Call to update the priority of the logging message to receive. @@ -310,7 +389,7 @@ OBSERVER_API void logObserverRequestScopes(unsigned long long target); * In this case the ID of the scope can be 0. * \param count The number of scope entries in the list. **/ -OBSERVER_API void logObserverRequestChangeScopePrio(unsigned long long target, const sLogScope* scopes, unsigned int count); +OBSERVER_API void logObserverRequestChangeScopePrio(ITEM_ID target, const sLogScope* scopes, uint32_t count); /** * \brief Call to save current configuration of the specified target. This is normally called when update the log priority of the instance, @@ -319,7 +398,7 @@ OBSERVER_API void logObserverRequestChangeScopePrio(unsigned long long target, c * If the target is ID_IGNORE (or 0), the request is sent to all connected instances. * Otherwise, should be indicated the valid cookie ID of the connected log instance. **/ -OBSERVER_API void logObserverRequestSaveConfig(unsigned long long target); +OBSERVER_API void logObserverRequestSaveConfig(ITEM_ID target); #endif // AREG_OBSERVER_LIB_LOGOBSERVERAPI_H diff --git a/framework/observer/lib/LogObserverSwitches.h b/framework/observer/lib/LogObserverSwitches.h index 35e0e8153..8ba60b7cf 100644 --- a/framework/observer/lib/LogObserverSwitches.h +++ b/framework/observer/lib/LogObserverSwitches.h @@ -125,7 +125,7 @@ #define OBSERVER_API_IMPL #endif // WIN32 -#if !defined(IMP_AREG_DLL) && !defined(IMP_AREG_LIB) +#if !defined(IMP_AREG_DLL) && !defined(IMP_AREG_LIB) && !defined(IMPORT_SHARED_SYMBOLS) && !defined(IMPORT_STATIC_SYMBOLS) #pragma message ("WARNING: Neither IMP_AREG_DLL, nor IMP_AREG_LIB is defined. Make proper settings. By default setting IMP_AREG_DLL.") #define IMP_AREG_DLL #endif // !defined(IMP_AREG_DLL) && !defined(IMP_AREG_LIB) diff --git a/framework/observer/lib/Makefile b/framework/observer/lib/Makefile index 12146227b..629f216b2 100644 --- a/framework/observer/lib/Makefile +++ b/framework/observer/lib/Makefile @@ -1,7 +1,6 @@ observer_lib_PROJECT_NAME := observerapi observer_lib_BASE := $(observer_BASE)/lib -observer_lib_TARGET_PATH := observer_lib_OUTPUT_OBJ := $(AREG_OUTPUT_OBJ)/$(observer_lib_PROJECT_NAME) observer_lib_SRC := @@ -13,14 +12,18 @@ observer_lib_CXXFLAGS := -I$(AREG_BASE) -D$(AREG_LIB_IMPORT) -fPIC observer_lib_LDFLAGS := $(AREG_TOOL_FLAGS) ifeq ($(AREG_OBSERVER_LIB), shared) - observer_lib_CXXFLAGS += -DEXP_OBSERVER_DLL + OBSERVER_API_IMPORT := -DIMP_OBSERVER_DLL + observer_lib_CXXFLAGS += -DEXP_OBSERVER_DLL + OBSERVER_API_PATH := $(AREG_OUTPUT_BIN) else - observer_lib_CXXFLAGS += -DEXP_OBSERVER_LIB + OBSERVER_API_IMPORT := -DIMP_OBSERVER_LIB + observer_lib_CXXFLAGS += -DEXP_OBSERVER_LIB + OBSERVER_API_PATH := $(AREG_OUTPUT_LIB) endif -observer_lib_TARGET_PATH := $(AREG_OUTPUT_BIN)/$(AREG_LIB_PREFIX)$(observer_lib_PROJECT_NAME)$(AREG_OBSERVER_LIB_EXT) +observer_lib_TARGET_BIN := $(OBSERVER_API_PATH)/$(AREG_LIB_PREFIX)$(observer_lib_PROJECT_NAME)$(AREG_OBSERVER_LIB_EXT) -observerapi: $(observer_lib_TARGET_PATH) +observerapi: $(observer_lib_TARGET_BIN) # define one target for each source file $(foreach cpp, $(observer_lib_SRC), $(eval $(call obj, $(cpp), $(observer_lib_OUTPUT_OBJ), observer_lib_OBJS, $(observer_lib_CXXFLAGS)))) @@ -28,7 +31,7 @@ $(foreach cpp, $(observer_lib_SRC), $(eval $(call obj, $(cpp), $(observer_lib_OU DEPS = $(observer_lib_OBJS:%.o=%.d) -include $(DEPS) -$(observer_lib_TARGET_PATH): $(AREG_DEPEND) $(observer_lib_OBJS) +$(observer_lib_TARGET_BIN): $(AREG_DEPEND) $(observer_lib_OBJS) @echo "Linking $(observer_lib_PROJECT_NAME) $(AREG_OBSERVER_LIB) library ..." @mkdir -p $(dir $@) if [ "$(AREG_OBSERVER_LIB)" = "shared" ]; then \ diff --git a/framework/observer/lib/private/LogObserverApi.cpp b/framework/observer/lib/private/LogObserverApi.cpp index 4659aba05..df0d73fc7 100644 --- a/framework/observer/lib/private/LogObserverApi.cpp +++ b/framework/observer/lib/private/LogObserverApi.cpp @@ -32,81 +32,148 @@ namespace { struct sLogObserverStruct { - Mutex losLock { false }; - bool losInitialized { false }; - sObserverEvents losEvents { }; + Mutex losLock { false }; + eObserverStates losState { eObserverStates::ObserverUninitialized }; + sObserverEvents losEvents { }; }; sLogObserverStruct theObserver; - void setCallbacks(const sObserverEvents* srcCallbacks, sObserverEvents & dstCallbacks) + void _setCallbacks(sObserverEvents & dstCallbacks, const sObserverEvents* srcCallbacks) { if (srcCallbacks != nullptr) { - dstCallbacks.evtServiceConnected = srcCallbacks->evtServiceConnected; - dstCallbacks.evtMessagingFailed = srcCallbacks->evtMessagingFailed; + dstCallbacks.evtObserverConfigured = srcCallbacks->evtObserverConfigured; + dstCallbacks.evtServiceConnected = srcCallbacks->evtServiceConnected; + dstCallbacks.evtLoggingStarted = srcCallbacks->evtLoggingStarted; + dstCallbacks.evtMessagingFailed = srcCallbacks->evtMessagingFailed; + dstCallbacks.evtInstConnected = srcCallbacks->evtInstConnected; + dstCallbacks.evtInstDisconnected = srcCallbacks->evtInstDisconnected; + dstCallbacks.evtLogScopes = srcCallbacks->evtLogScopes; + dstCallbacks.evtLogMessage = srcCallbacks->evtLogMessage; + dstCallbacks.evtLogMessageEx = srcCallbacks->evtLogMessageEx; } else { - dstCallbacks.evtServiceConnected = nullptr; - dstCallbacks.evtMessagingFailed = nullptr; + dstCallbacks.evtObserverConfigured = nullptr; + dstCallbacks.evtServiceConnected = nullptr; + dstCallbacks.evtLoggingStarted = nullptr; + dstCallbacks.evtMessagingFailed = nullptr; + dstCallbacks.evtInstConnected = nullptr; + dstCallbacks.evtInstDisconnected = nullptr; + dstCallbacks.evtLogScopes = nullptr; + dstCallbacks.evtLogMessage = nullptr; + dstCallbacks.evtLogMessageEx = nullptr; } } + + inline bool _isInitialized(eObserverStates state) + { + return (state != eObserverStates::ObserverUninitialized); + } + + inline bool _isDisconnected(eObserverStates state) + { + return (state == eObserverStates::ObserverDisconnected); + } + + inline bool _isConnected(eObserverStates state) + { + return (state >= eObserverStates::ObserverConnected); + } + + inline bool _isStarted(eObserverStates state) + { + return (state == eObserverStates::ObserverConnected); + } } OBSERVER_API_IMPL bool logObserverInitialize(const sObserverEvents * callbacks, const char* configFilePath /* = nullptr */) { Lock lock(theObserver.losLock); - if (theObserver.losInitialized == false) + if (_isInitialized(theObserver.losState) == false) { - theObserver.losInitialized = true; - setCallbacks(callbacks, theObserver.losEvents); - Application::initApplication(true, false, false, true, false, configFilePath); - LoggerClient& client = LoggerClient::getInstance(); + theObserver.losState = eObserverStates::ObserverDisconnected; + _setCallbacks(theObserver.losEvents, callbacks); client.setCallbacks(&theObserver.losEvents); + Application::initApplication(true, false, false, true, false, configFilePath, static_cast(&client)); } - return theObserver.losInitialized; + return _isInitialized(theObserver.losState); } -OBSERVER_API_IMPL bool logObserverConnectLogger(const char* ipAddress /*= nullptr*/, unsigned short portNr /* = 0 */) +OBSERVER_API_IMPL bool logObserverConnectLogger(const char* ipAddress /*= nullptr*/, uint16_t portNr /* = 0 */) { - return LoggerClient::getInstance().startLoggerClient(ipAddress, portNr); + Lock lock(theObserver.losLock); + + if (_isDisconnected(theObserver.losState)) + { + if (LoggerClient::getInstance().startLoggerClient(ipAddress, portNr)) + { + theObserver.losState = eObserverStates::ObserverConnected; + } + } + + return _isConnected(theObserver.losState); } OBSERVER_API_IMPL void logObserverDisconnectLogger() { - LoggerClient::getInstance().stopLoggerClient(); + Lock lock(theObserver.losLock); + + if (_isConnected(theObserver.losState)) + { + LoggerClient& client = LoggerClient::getInstance(); + client.stopLoggerClient(); + theObserver.losState = eObserverStates::ObserverDisconnected; + } +} + +OBSERVER_API_IMPL void logObserverPauseLogging(bool doPause) +{ + Lock lock(theObserver.losLock); + + if (_isConnected(theObserver.losState)) + { + theObserver.losState = doPause ? eObserverStates::ObserverPaused : eObserverStates::ObserverConnected; + LoggerClient::getInstance().setPaused(doPause); + } +} + +OBSERVER_API_IMPL eObserverStates logObserverCurrentState() +{ + Lock lock(theObserver.losLock); + return theObserver.losState; } OBSERVER_API_IMPL void logObserverRelease() { Lock lock(theObserver.losLock); - if (theObserver.losInitialized) + if (_isInitialized(theObserver.losState)) { LoggerClient& client = LoggerClient::getInstance(); client.setCallbacks(nullptr); client.stopLoggerClient(); Application::releaseApplication(); - setCallbacks(nullptr, theObserver.losEvents); - theObserver.losInitialized = false; + _setCallbacks(theObserver.losEvents, nullptr); + theObserver.losState = eObserverStates::ObserverUninitialized; } } OBSERVER_API_IMPL bool logObserverIsInitialized() { Lock lock(theObserver.losLock); - return theObserver.losInitialized; + return _isInitialized(theObserver.losState); } OBSERVER_API_IMPL bool logObserverIsConnected() { Lock lock(theObserver.losLock); bool result{ false }; - if (theObserver.losInitialized) + if (_isInitialized(theObserver.losState)) { LoggerClient& client = LoggerClient::getInstance(); result = client.isConnectedState(); @@ -115,11 +182,17 @@ OBSERVER_API_IMPL bool logObserverIsConnected() return result; } +OBSERVER_API_IMPL bool logObserverIsStarted() +{ + Lock lock(theObserver.losLock); + return _isStarted(theObserver.losState); +} + OBSERVER_API_IMPL const char* logObserverLoggerAddress() { Lock lock(theObserver.losLock); const char * result{ nullptr }; - if (theObserver.losInitialized) + if (_isInitialized(theObserver.losState)) { LoggerClient& client = LoggerClient::getInstance(); result = client.getAddress().getHostAddress().getString(); @@ -132,7 +205,7 @@ OBSERVER_API_IMPL unsigned short logObserverLoggerPort() { Lock lock(theObserver.losLock); unsigned short result{ NESocket::InvalidPort }; - if (theObserver.losInitialized) + if (_isInitialized(theObserver.losState)) { LoggerClient& client = LoggerClient::getInstance(); result = client.getAddress().getHostPort(); @@ -145,7 +218,7 @@ OBSERVER_API_IMPL bool logObserverConfigLoggerEnabled() { Lock lock(theObserver.losLock); bool result{ false }; - if (theObserver.losInitialized) + if (_isInitialized(theObserver.losState)) { LoggerClient& client = LoggerClient::getInstance(); result = client.isConfigLoggerConnectEnabled(); @@ -154,17 +227,17 @@ OBSERVER_API_IMPL bool logObserverConfigLoggerEnabled() return result; } -OBSERVER_API_IMPL bool logObserverConfigLoggerAddress(char* addrBuffer, int count) +OBSERVER_API_IMPL bool logObserverConfigLoggerAddress(char* addrBuffer, uint32_t space) { Lock lock(theObserver.losLock); bool result{ false }; - if (theObserver.losInitialized) + if (_isInitialized(theObserver.losState)) { LoggerClient& client = LoggerClient::getInstance(); String addr{ client.getConfigLoggerAddress() }; - if ((addrBuffer != nullptr) && (addr.getLength() > static_cast(count))) + if ((addrBuffer != nullptr) && (addr.getLength() > static_cast(space))) { - result = NEString::copyString(addrBuffer, count, addr.getString(), addr.getLength()) > 0; + result = NEString::copyString(addrBuffer, space, addr.getString(), addr.getLength()) > 0; } } @@ -175,7 +248,7 @@ OBSERVER_API_IMPL unsigned short logObserverConfigLoggerPort() { Lock lock(theObserver.losLock); uint16_t result{ NESocket::InvalidPort }; - if (theObserver.losInitialized) + if (_isInitialized(theObserver.losState)) { LoggerClient& client = LoggerClient::getInstance(); result = client.getConfigLoggerPort(); @@ -187,25 +260,25 @@ OBSERVER_API_IMPL unsigned short logObserverConfigLoggerPort() OBSERVER_API_IMPL void logObserverRequestInstances() { Lock lock(theObserver.losLock); - if (theObserver.losInitialized) + if (_isInitialized(theObserver.losState)) { LoggerClient::getInstance().requestConnectedInstances(); } } -OBSERVER_API_IMPL void logObserverRequestScopes(unsigned long long target /* = ID_IGNORED */) +OBSERVER_API_IMPL void logObserverRequestScopes(ITEM_ID target /* = ID_IGNORED */) { Lock lock(theObserver.losLock); - if (theObserver.losInitialized) + if (_isInitialized(theObserver.losState)) { LoggerClient::getInstance().requestScopes(target); } } -OBSERVER_API_IMPL void logObserverRequestChangeScopePrio(unsigned long long target, const sLogScope* scopes, unsigned int count) +OBSERVER_API_IMPL void logObserverRequestChangeScopePrio(ITEM_ID target, const sLogScope* scopes, uint32_t count) { Lock lock(theObserver.losLock); - if (theObserver.losInitialized && (target != ID_IGNORE)) + if (_isInitialized(theObserver.losState) && (target != ID_IGNORE)) { NETrace::ScopeNames scopeList(count); for (uint32_t i = 0; i < count; ++i) @@ -217,10 +290,10 @@ OBSERVER_API_IMPL void logObserverRequestChangeScopePrio(unsigned long long targ } } -OBSERVER_API_IMPL void logObserverRequestSaveConfig(unsigned long long target /* = ID_IGNORED */) +OBSERVER_API_IMPL void logObserverRequestSaveConfig(ITEM_ID target /* = ID_IGNORED */) { Lock lock(theObserver.losLock); - if (theObserver.losInitialized) + if (_isInitialized(theObserver.losState)) { LoggerClient::getInstance().requestSaveConfiguration(target); } diff --git a/framework/observer/lib/private/LoggerClient.cpp b/framework/observer/lib/private/LoggerClient.cpp index 4bbdbaeb1..10ca1969e 100644 --- a/framework/observer/lib/private/LoggerClient.cpp +++ b/framework/observer/lib/private/LoggerClient.cpp @@ -14,10 +14,12 @@ * The logger service connection client. ************************************************************************/ +/************************************************************************ + * Include files. + ************************************************************************/ #include "observer/lib/private/LoggerClient.hpp" #include "areg/ipc/ConnectionConfiguration.hpp" -#include "areg/trace/NETrace.hpp" #include "observer/lib/LogObserverApi.h" #define IS_VALID(callback) ((mCallbacks != nullptr) && ((callback) != nullptr)) @@ -37,24 +39,29 @@ LoggerClient::LoggerClient(void) , static_cast(self()) , static_cast(self()) , ThreadPrefix) + , IEConfigurationListener ( ) , DispatcherThread ( ThreadName ) , IEServiceConnectionConsumer( ) , IERemoteMessageHandler ( ) , mCallbacks ( nullptr ) , mMessageProcessor ( self() ) + , mIsPaused ( false ) { } bool LoggerClient::startLoggerClient(const String & address /*= String::EmptyString*/, uint16_t portNr /*= NESocket::InvalidPort*/) { - Lock lock(mLock); if ((address.isEmpty() == false) && (portNr != NESocket::InvalidPort)) { + Lock lock(mLock); + mIsPaused = false; applyServiceConnectionData(address, portNr); } else { + Lock lock(mLock); + mIsPaused = false; ConnectionConfiguration config(LoggerClient::ServiceType, LoggerClient::ConnectType); if (config.isConfigured()) { @@ -67,7 +74,12 @@ bool LoggerClient::startLoggerClient(const String & address /*= String::EmptyStr void LoggerClient::stopLoggerClient(void) { - Lock lock(mLock); + do + { + Lock lock(mLock); + mIsPaused = false; + } while (false); + disconnectServiceHost(); } @@ -77,6 +89,28 @@ void LoggerClient::setCallbacks(const sObserverEvents* callbacks) mCallbacks = callbacks; } +void LoggerClient::setPaused(bool doPause) +{ + FuncObserverStarted evtStart{ nullptr }; + bool isStarted{ false }; + + do + { + Lock lock(mLock); + mIsPaused = doPause; + if (mCallbacks != nullptr) + { + evtStart = isConnectionStarted() ? mCallbacks->evtLoggingStarted : nullptr; + isStarted = mIsPaused; + } + } while (false); + + if (evtStart != nullptr) + { + evtStart(isStarted); + } +} + const NESocket::SocketAddress& LoggerClient::getAddress(void) const { Lock lock(mLock); @@ -125,6 +159,7 @@ void LoggerClient::requestConnectedInstances(void) void LoggerClient::requestScopes(const ITEM_ID& target /*= NEService::COOKIE_ANY*/) { + Lock lock(mLock); if ((mChannel.getCookie() != NEService::COOKIE_UNKNOWN) && (target != NEService::COOKIE_UNKNOWN)) { sendMessage(NETrace::messageQueryScopes(mChannel.getCookie(), target == NEService::COOKIE_ANY ? LoggerClient::TargetID : target)); @@ -133,6 +168,7 @@ void LoggerClient::requestScopes(const ITEM_ID& target /*= NEService::COOKIE_ANY void LoggerClient::requestChangeScopePrio(const NETrace::ScopeNames & scopes, const ITEM_ID& target /*= NEService::COOKIE_ANY*/) { + Lock lock(mLock); if ((mChannel.getCookie() != NEService::COOKIE_UNKNOWN) && (target != NEService::COOKIE_UNKNOWN)) { sendMessage(NETrace::messageUpdateScopes(mChannel.getCookie(), target == NEService::COOKIE_ANY ? LoggerClient::TargetID : target, scopes)); @@ -141,12 +177,60 @@ void LoggerClient::requestChangeScopePrio(const NETrace::ScopeNames & scopes, co void LoggerClient::requestSaveConfiguration(const ITEM_ID& target /*= NEService::COOKIE_ANY*/) { + Lock lock(mLock); if ((mChannel.getCookie() != NEService::COOKIE_UNKNOWN) && (target != NEService::COOKIE_UNKNOWN)) { sendMessage(NETrace::messageSaveConfiguration(mChannel.getCookie(), target == NEService::COOKIE_ANY ? LoggerClient::TargetID : target)); } } +void LoggerClient::prepareSaveConfiguration(ConfigManager& config) +{ +} + +void LoggerClient::postSaveConfiguration(ConfigManager& config) +{ +} + +void LoggerClient::prepareReadConfiguration(ConfigManager& config) +{ +} + +void LoggerClient::postReadConfiguration(ConfigManager& config) +{ + FuncObserverConfigured evtConfig{ nullptr }; + String address; + uint16_t port; + + config.setLogEnabled(NETrace::eLogingTypes::LogTypeFile, true, true); + config.setLogEnabled(NETrace::eLogingTypes::LogTypeRemote, false, true); + + do + { + Lock lock(mLock); + if (mCallbacks != nullptr) + { + evtConfig = mCallbacks->evtObserverConfigured; + address = config.getRemoteServiceAddress(LoggerClient::ServiceType, LoggerClient::ConnectType); + port = config.getRemoteServicePort(LoggerClient::ServiceType, LoggerClient::ConnectType); + } + } while (false); + + if (evtConfig != nullptr) + { + evtConfig(address.getString(), port); + } +} + +void LoggerClient::onSetupConfiguration(const NEPersistence::ListProperties& listReadonly, const NEPersistence::ListProperties& listWritable, ConfigManager& config) +{ +} + +bool LoggerClient::postEvent(Event& eventElem) +{ + return EventDispatcher::postEvent(eventElem); +} + void LoggerClient::readyForEvents(bool isReady) { if (isReady) @@ -203,51 +287,123 @@ void LoggerClient::onServiceExit(void) void LoggerClient::connectedRemoteServiceChannel(const Channel& channel) { - Lock lock(mLock); - if (IS_VALID(mCallbacks->evtServiceConnected)) + FuncServiceConnected evtConnect{ nullptr }; + FuncObserverStarted evtStart{ nullptr }; + String address; + uint16_t port{ NESocket::InvalidPort }; + bool isStarted{ false }; + + do + { + Lock lock(mLock); + if (mCallbacks != nullptr) + { + evtConnect = mCallbacks->evtServiceConnected; + evtStart = mCallbacks->evtLoggingStarted; + const NESocket::SocketAddress& addr{ mClientConnection.getAddress() }; + address = addr.getHostAddress(); + port = addr.getHostPort(); + isStarted = mIsPaused = false; + } + } while (false); + + sendMessage(NETrace::messageQueryInstances(channel.getCookie(), LoggerClient::TargetID)); + if (evtConnect != nullptr) { - const NESocket::SocketAddress& addr{ mClientConnection.getAddress() }; - mCallbacks->evtServiceConnected(true, addr.getHostAddress().getString(), addr.getHostPort()); + evtConnect(true, address.getString(), port); + } - sendMessage(NETrace::messageQueryInstances(channel.getCookie(), LoggerClient::TargetID)); + if (evtStart != nullptr) + { + evtStart(isStarted); } } void LoggerClient::disconnectedRemoteServiceChannel(const Channel& channel) { - Lock lock(mLock); - if (IS_VALID(mCallbacks->evtServiceConnected)) + FuncServiceConnected evtConnect{ nullptr }; + FuncObserverStarted evtStart{ nullptr }; + String address; + uint16_t port{ NESocket::InvalidPort }; + + do + { + Lock lock(mLock); + if (mCallbacks != nullptr) + { + evtConnect = mCallbacks->evtServiceConnected; + evtStart = mCallbacks->evtLoggingStarted; + const NESocket::SocketAddress& addr{ mClientConnection.getAddress() }; + address = addr.getHostAddress(); + port = addr.getHostPort(); + } + } while (false); + + if (evtStart != nullptr) + { + evtStart(false); + } + + if (evtConnect != nullptr) { - const NESocket::SocketAddress& addr{ mClientConnection.getAddress() }; - mCallbacks->evtServiceConnected(false, addr.getHostAddress().getString(), addr.getHostPort()); + evtConnect(false, address.getString(), port); } } void LoggerClient::lostRemoteServiceChannel(const Channel& channel) { - Lock lock(mLock); - if (IS_VALID(mCallbacks->evtServiceConnected)) + FuncObserverStarted evtStart{ nullptr }; + + do + { + Lock lock(mLock); + if (mCallbacks != nullptr) + { + evtStart = mCallbacks->evtLoggingStarted; + } + } while (false); + + if (evtStart != nullptr) { - const NESocket::SocketAddress& addr{ mClientConnection.getAddress() }; - mCallbacks->evtServiceConnected(false, addr.getHostAddress().getString(), addr.getHostPort()); + evtStart(false); } } void LoggerClient::failedSendMessage(const RemoteMessage& msgFailed, Socket& whichTarget) { - Lock lock(mLock); - if (IS_VALID(mCallbacks->evtMessagingFailed)) + FuncMessagingFailed evtFailed{ nullptr }; + do + { + Lock lock(mLock); + if (mCallbacks != nullptr) + { + evtFailed = mCallbacks->evtMessagingFailed; + } + } while (false); + + + if (evtFailed) { - mCallbacks->evtMessagingFailed(); + evtFailed(); } } void LoggerClient::failedReceiveMessage(Socket& whichSource) { - Lock lock(mLock); - if (IS_VALID(mCallbacks->evtMessagingFailed)) + FuncMessagingFailed evtFailed{ nullptr }; + do + { + Lock lock(mLock); + if (mCallbacks != nullptr) + { + evtFailed = mCallbacks->evtMessagingFailed; + } + } while (false); + + + if (evtFailed) { - mCallbacks->evtMessagingFailed(); + evtFailed(); } } @@ -275,7 +431,10 @@ void LoggerClient::processReceivedMessage(const RemoteMessage& msgReceived, Sock break; case NEService::eFuncIdRange::ServiceLogMessage: - mMessageProcessor.notifyLogMessage(msgReceived); + if (mIsPaused == false) + { + mMessageProcessor.notifyLogMessage(msgReceived); + } break; default: diff --git a/framework/observer/lib/private/LoggerClient.hpp b/framework/observer/lib/private/LoggerClient.hpp index 9220ca6b5..226604021 100644 --- a/framework/observer/lib/private/LoggerClient.hpp +++ b/framework/observer/lib/private/LoggerClient.hpp @@ -25,10 +25,10 @@ #include "areg/ipc/ServiceClientConnectionBase.hpp" #include "areg/ipc/IEServiceConnectionConsumer.hpp" #include "areg/ipc/IERemoteMessageHandler.hpp" +#include "areg/persist/IEConfigurationListener.hpp" #include "areg/trace/NETrace.hpp" -#include "areg/base/SynchObjects.hpp" #include "observer/lib/private/ObserverMessageProcessor.hpp" /************************************************************************ @@ -46,6 +46,7 @@ struct sObserverEvents; * structure of callbacks to trigger when an event happens. **/ class LoggerClient : public ServiceClientConnectionBase + , public IEConfigurationListener , protected DispatcherThread , protected IEServiceConnectionConsumer , protected IERemoteMessageHandler @@ -128,6 +129,13 @@ class LoggerClient : public ServiceClientConnectionBase **/ void setCallbacks(const sObserverEvents * callbacks); + /** + * \brief Set paused flag true or false. If logger client is paused, it does not + * write logs in the file, but remain connected. + * \param doPause The paused flag to set. + **/ + void setPaused(bool doPause); + /** * \brief Returns the socket address (IP address and port number) to connect to the logger service. * The connection might be not established yet. @@ -190,10 +198,58 @@ class LoggerClient : public ServiceClientConnectionBase // Overrides ////////////////////////////////////////////////////////////////////////// protected: +/************************************************************************/ +// IEConfigurationListener interface overrides +/************************************************************************/ + + /** + * \brief Called by configuration manager before the configuration is saved in the file. + * \param config The instance of configuration manager. + **/ + virtual void prepareSaveConfiguration(ConfigManager& config) override; + + /** + * \brief Called by configuration manager after the configuration is saved in the file. + * \param config The instance of configuration manager. + **/ + virtual void postSaveConfiguration(ConfigManager& config) override; + + /** + * \brief Called by configuration manager before the configuration is loaded from the file. + * \param config The instance of configuration manager. + **/ + virtual void prepareReadConfiguration(ConfigManager& config) override; + + /** + * \brief Called by configuration manager when configuration is completed to load data from the file. + * \param config The instance of configuration manager. + **/ + virtual void postReadConfiguration(ConfigManager& config) override; + + /** + * \brief Called by configuration manager after setting read-only and writable properties. + * For example, when the default configuration is set. + * \param listReadonly The list of read-only properties to set in the configuration. + * \param listWritable The list of module / process specific properties to set in the configuration; + * \param config The instance of configuration manager. + **/ + virtual void onSetupConfiguration(const NEPersistence::ListProperties& listReadonly, const NEPersistence::ListProperties& listWritable, ConfigManager& config) override; + /************************************************************************/ // DispatcherThread overrides /************************************************************************/ + /** + * \brief Posts event and delivers to its target. + * Since the Dispatcher Thread is a Base object for + * Worker and Component threads, it does nothing + * and only destroys event object without processing. + * Override this method or use Worker / Component thread. + * \param eventElem Event object to post + * \return In this class it always returns true. + **/ + virtual bool postEvent(Event& eventElem) override; + /** * \brief Call to enable or disable event dispatching threads to receive events. * Override if need to make event dispatching preparation job. @@ -298,6 +354,11 @@ class LoggerClient : public ServiceClientConnectionBase **/ ObserverMessageProcessor mMessageProcessor; + /** + * \brief The flag, indicating whether the observer was paused or not. + **/ + bool mIsPaused; + ////////////////////////////////////////////////////////////////////////// // Forbidden calls. ////////////////////////////////////////////////////////////////////////// diff --git a/framework/observer/lib/private/ObserverMessageProcessor.cpp b/framework/observer/lib/private/ObserverMessageProcessor.cpp index 555e17fc9..ea9b0fcb4 100644 --- a/framework/observer/lib/private/ObserverMessageProcessor.cpp +++ b/framework/observer/lib/private/ObserverMessageProcessor.cpp @@ -14,19 +14,18 @@ * The log observer message processor. ************************************************************************/ - /************************************************************************ - * Include files. - ************************************************************************/ +/************************************************************************ + * Include files. + ************************************************************************/ #include "observer/lib/private/ObserverMessageProcessor.hpp" #include "areg/base/RemoteMessage.hpp" -#include "areg/base/SynchObjects.hpp" -#include "areg/base/TEArrayList.hpp" #include "areg/component/NEService.hpp" +#include "areg/ipc/NERemoteService.hpp" #include "areg/trace/TraceScope.hpp" -#include "observer/lib/private/LoggerClient.hpp" #include "observer/lib/LogObserverApi.h" +#include "observer/lib/private/LoggerClient.hpp" #define IS_VALID(callback) ((mLoggerClient.mCallbacks != nullptr) && ((callback) != nullptr)) @@ -38,124 +37,187 @@ ObserverMessageProcessor::ObserverMessageProcessor(LoggerClient& loggerClient) void ObserverMessageProcessor::notifyServiceConnection(const RemoteMessage& msgReceived) { - ITEM_ID cookie{ NEService::COOKIE_UNKNOWN }; - NEService::eServiceConnection connection{ NEService::eServiceConnection::ServiceConnectionUnknown }; - msgReceived >> cookie; - msgReceived >> connection; + mLoggerClient.serviceConnectionEvent(msgReceived); +} + +void ObserverMessageProcessor::notifyConnectedClients(const RemoteMessage& msgReceived) +{ + FuncInstancesConnect evtInstConnected{ nullptr }; + FuncInstancesDisconnect evtInstDisconnected{ nullptr }; + + sLogInstance* listConnect{ nullptr }; + ITEM_ID* listDisconnect{ nullptr }; + NERemoteService::eRemoteConnection remConnect{ NERemoteService::eRemoteConnection::RemoteDisconnected }; + uint32_t count{ 0 }; - switch (connection) + do { - case NEService::eServiceConnection::ServiceConnected: - case NEService::eServiceConnection::ServicePending: + Lock lock(mLoggerClient.mLock); + if (mLoggerClient.mCallbacks != nullptr) { - if (msgReceived.getResult() == NEMemory::MESSAGE_SUCCESS) + msgReceived >> remConnect; + msgReceived >> count; + + if (remConnect == NERemoteService::eRemoteConnection::RemoteConnected) { - ASSERT(cookie == msgReceived.getTarget()); - mLoggerClient.mClientConnection.setCookie(cookie); - mLoggerClient.sendCommand(ServiceEventData::eServiceEventCommands::CMD_ServiceStarted); + evtInstConnected = mLoggerClient.mCallbacks->evtInstConnected; + listConnect = count != 0 ? new sLogInstance[count] : nullptr; + if (listConnect != nullptr) + { + for (uint32_t i = 0; i < count; ++i) + { + sLogInstance& inst{ listConnect[i] }; + NEService::sServiceConnectedInstance instance{}; + msgReceived >> instance; + inst.liSource = static_cast(instance.ciSource); + inst.liBitness = static_cast(instance.ciBitness); + inst.liCookie = instance.ciCookie; + inst.liTimestamp= instance.ciTimestamp; + NEString::copyString( inst.liName + , static_cast(LENGTH_NAME) + , instance.ciInstance.getString() + , static_cast(instance.ciInstance.getLength())); + NEString::copyString( inst.liLocation + , static_cast(LENGTH_LOCATION) + , instance.ciLocation.getString() + , static_cast(instance.ciLocation.getLength())); + } + } + else + { + count = 0; + } } else { - mLoggerClient.cancelConnection(); - mLoggerClient.sendCommand(ServiceEventData::eServiceEventCommands::CMD_ServiceLost); + evtInstDisconnected = mLoggerClient.mCallbacks->evtInstDisconnected; + listDisconnect = new ITEM_ID[count]; + if (listDisconnect != nullptr) + { + for (uint32_t i = 0; i < count; ++i) + { + msgReceived >> listDisconnect[i]; + } + } + else + { + count = 0; + } } } - break; + } while (false); - case NEService::eServiceConnection::ServiceRejected: + if (evtInstConnected != nullptr) + { + ASSERT(evtInstDisconnected == nullptr); + ASSERT(listDisconnect == nullptr); + evtInstConnected(static_cast(listConnect), count); + if (listConnect != nullptr) { - mLoggerClient.cancelConnection(); - mLoggerClient.sendCommand(ServiceEventData::eServiceEventCommands::CMD_ServiceStopped); + delete[] listConnect; } - break; - - default: + } + else if (evtInstDisconnected != nullptr) + { + ASSERT(evtInstConnected == nullptr); + ASSERT(listConnect == nullptr); + evtInstDisconnected(static_cast(listDisconnect), count); + if (listDisconnect != nullptr) { - mLoggerClient.cancelConnection(); - mLoggerClient.sendCommand(ServiceEventData::eServiceEventCommands::CMD_ServiceLost); + delete[] listDisconnect; } - break; } } -void ObserverMessageProcessor::notifyConnectedClients(const RemoteMessage& msgReceived) +void ObserverMessageProcessor::notifyLogRegisterScopes(const RemoteMessage& msgReceived) { - if (IS_VALID(mLoggerClient.mCallbacks->evtLogSources)) - { - uint32_t count{ 0 }; - msgReceived >> count; + FuncLogScopes evtScopes{ nullptr }; + ITEM_ID cookie{ msgReceived.getSource() }; + sLogScope* scopes{ nullptr }; + uint32_t count{ 0 }; - sLogInstance* list = new sLogInstance[count]; - if (list != nullptr) + do + { + Lock lock(mLoggerClient.mLock); + if (mLoggerClient.mCallbacks != nullptr) { - for (uint32_t i = 0; i < count; ++i) + evtScopes = mLoggerClient.mCallbacks->evtLogScopes; + msgReceived >> count; + scopes = count != 0 ? new sLogScope[count] : nullptr; + if (scopes != nullptr) { - NEService::sServiceConnectedInstance instance{}; - msgReceived >> instance; - list[i].liSource = static_cast(instance.ciSource); - list[i].liBitness = static_cast(instance.ciBitness); - list[i].liCookie = instance.ciCookie; - NEString::copyString( list[i].liName - , static_cast(LENGTH_NAME) - , instance.ciInstance.getString() - , static_cast(instance.ciInstance.getLength())); - NEString::copyString( list[i].liLocation - , static_cast(LENGTH_LOCATION) - , instance.ciLocation.getString() - , static_cast(instance.ciLocation.getLength())); + for (uint32_t i = 0; i < count; ++i) + { + TraceScope scope(msgReceived); + scopes[i].lsId = scope.getScopeId(); + scopes[i].lsPrio = scope.getPriority(); + NEString::copyString(scopes[i].lsName, static_cast(LENGTH_SCOPE), scope.getScopeName().getString(), scope.getScopeName().getLength()); + } + } + else + { + count = 0; } } + } while (false); - mLoggerClient.mCallbacks->evtLogSources(list, list != nullptr ? count : 0); - delete[] list; + if (evtScopes != nullptr) + { + evtScopes(cookie, scopes, count); + if (scopes != nullptr) + { + delete[] scopes; + } } } -void ObserverMessageProcessor::notifyLogRegisterScopes(const RemoteMessage& msgReceived) +void ObserverMessageProcessor::notifyLogMessage(const RemoteMessage& msgReceived) { - if (IS_VALID(mLoggerClient.mCallbacks->evtLogScopes)) + FuncLogMessage evtMessage{ nullptr }; + FuncLogMessageEx evtMessageEx{ nullptr }; + sLogMessage msgLog{ }; + const unsigned char* logBuffer{ nullptr }; + unsigned int size{ 0 }; + + do { - ITEM_ID cookie{ msgReceived.getSource() }; - uint32_t count{ 0 }; - msgReceived >> count; - sLogScope* scopes = new sLogScope[count]; - if (scopes != nullptr) + Lock lock(mLoggerClient.mLock); + if (mLoggerClient.mCallbacks != nullptr) { - for (uint32_t i = 0; i < count; ++i) + if (mLoggerClient.mCallbacks->evtLogMessage != nullptr) { - TraceScope scope(msgReceived); - scopes[i].lsId = scope.getScopeId(); - scopes[i].lsPrio = scope.getPriority(); - NEString::copyString(scopes[i].lsName, static_cast(LENGTH_SCOPE), scope.getScopeName().getString(), scope.getScopeName().getLength()); + evtMessage = mLoggerClient.mCallbacks->evtLogMessage; + const NETrace::sLogMessage* msgRemote = reinterpret_cast(msgReceived.getBuffer()); + ASSERT(msgRemote != nullptr); + + msgLog.msgType = static_cast(msgRemote->logMsgType); + msgLog.msgPriority = static_cast(msgRemote->logMessagePrio); + msgLog.msgSource = static_cast(msgRemote->logSource); + msgLog.msgCookie = static_cast(msgRemote->logCookie); + msgLog.msgModuleId = static_cast(msgRemote->logModuleId); + msgLog.msgThreadId = static_cast(msgRemote->logThreadId); + msgLog.msgTimestamp = static_cast(msgRemote->logTimestamp); + msgLog.msgScopeId = static_cast(msgRemote->logScopeId); + + NEString::copyString(msgLog.msgLogText, LENGTH_MESSAGE, msgRemote->logMessage, msgRemote->logMessageLen); + NEString::copyString(msgLog.msgThread, LENGTH_NAME, msgRemote->logThread, msgRemote->logThreadLen); + NEString::copyString(msgLog.msgModule, LENGTH_NAME, msgRemote->logModule, msgRemote->logModuleLen); + } + else if (mLoggerClient.mCallbacks->evtLogMessageEx != nullptr) + { + evtMessageEx = mLoggerClient.mCallbacks->evtLogMessageEx; + logBuffer = msgReceived.getBuffer(); + size = msgReceived.getSizeUsed(); } } + } while (false); - mLoggerClient.mCallbacks->evtLogScopes(cookie, scopes, scopes != nullptr ? count : 0u); - delete[] scopes; + if (evtMessage != nullptr) + { + evtMessage(&msgLog); } -} - -void ObserverMessageProcessor::notifyLogMessage(const RemoteMessage& msgReceived) -{ - if (IS_VALID(mLoggerClient.mCallbacks->evtLogMessage)) + else if (evtMessageEx != nullptr) { - const NETrace::sLogMessage * msgRemote = reinterpret_cast(msgReceived.getBuffer()); - ASSERT(msgRemote != nullptr); - - sLogMessage msgLog{ }; - msgLog.msgType = static_cast(msgRemote->logMsgType); - msgLog.msgPriority = static_cast(msgRemote->logMessagePrio); - msgLog.msgSource = static_cast(msgRemote->logSource); - msgLog.msgCookie = static_cast(msgRemote->logCookie); - msgLog.msgModuleId = static_cast(msgRemote->logModuleId); - msgLog.msgThreadId = static_cast(msgRemote->logThreadId); - msgLog.msgTimestamp = static_cast(msgRemote->logTimestamp); - msgLog.msgScopeId = static_cast(msgRemote->logScopeId); - - NEString::copyString(msgLog.msgLogText, LENGTH_MESSAGE, msgRemote->logMessage, msgRemote->logMessageLen); - NEString::copyString(msgLog.msgThread, LENGTH_NAME, msgRemote->logThread, msgRemote->logThreadLen); - NEString::copyString(msgLog.msgModule, LENGTH_NAME, msgRemote->logModule, msgRemote->logModuleLen); - - mLoggerClient.mCallbacks->evtLogMessage(&msgLog); + evtMessageEx(logBuffer, size); } } diff --git a/msvc_setup.props b/msvc_setup.props index 0c22c72b1..592906300 100644 --- a/msvc_setup.props +++ b/msvc_setup.props @@ -57,12 +57,12 @@ - + 1 - + 1