Explorar o código

HPCC-21498 Write a tank file in ESP logging manager

Also fix bugs in filterLogContent():
1. Both logBackEndReq flag and logBackEndResp flag are filters;
2. The ESPLCGBackEndReq should not be in a filter loop because
it has been handled separately;
3. Renamed the hasFilters flag to foundGroupFilters;
4. The ESPContext tree itself already has the /ESPContext node
as the top tree node. If no filter for ESPLCGESPContext, the
existing code creates another /ESPContext node on the top of
the ESPContext tree before adding the tree to the logContentTree.

Signed-off-by: wangkx <kevin.wang@lexisnexis.com>
wangkx %!s(int64=6) %!d(string=hai) anos
pai
achega
62bc3858d8

+ 1 - 0
esp/logging/logginglib/CMakeLists.txt

@@ -36,6 +36,7 @@ ADD_DEFINITIONS ( -D_USRDLL -DLOGGINGCOMMON_EXPORTS )
 set ( SRCS
     ${ESPSCM_GENERATED_DIR}/ws_loggingservice_esp.cpp
     ${HPCC_SOURCE_DIR}/esp/logging/logginglib/datafieldmap.cpp
+    ${HPCC_SOURCE_DIR}/esp/logging/logginglib/compressutil.cpp
     ${HPCC_SOURCE_DIR}/esp/logging/logginglib/loggingagentbase.cpp
     ${HPCC_SOURCE_DIR}/esp/logging/logginglib/LogSerializer.cpp
     ${HPCC_SOURCE_DIR}/esp/logging/logginglib/LogFailSafe.cpp

+ 5 - 5
esp/logging/logginglib/LogFailSafe.cpp

@@ -275,7 +275,7 @@ void CLogFailSafe::SplitLogRecord(const char* requestStr,StringBuffer& GUID, Str
     SplitRecord(requestStr,GUID,Cache);
 }
 
-void CLogFailSafe::Add(const char* GUID,IInterface& pIn)
+void CLogFailSafe::Add(const char* GUID,IInterface& pIn, CLogRequestInFile* reqInFile)
 {
     CSoapRequestBinding* reqObj = dynamic_cast<CSoapRequestBinding*>(&pIn);
     if (reqObj == 0)
@@ -283,10 +283,10 @@ void CLogFailSafe::Add(const char* GUID,IInterface& pIn)
 
     StringBuffer dataStr;
     reqObj->serializeContent(NULL,dataStr,NULL);
-    Add(GUID, dataStr);
+    Add(GUID, dataStr, reqInFile);
 }
 
-void CLogFailSafe::Add(const char* GUID, const StringBuffer& strContents)
+void CLogFailSafe::Add(const char* GUID, const StringBuffer& strContents, CLogRequestInFile* reqInFile)
 {
     VStringBuffer dataStr("<cache>%s</cache>", strContents.str());
 
@@ -302,12 +302,12 @@ void CLogFailSafe::Add(const char* GUID, const StringBuffer& strContents)
         if (fileSize > safeRolloverSizeThreshold)
             SafeRollover();
     }
-    m_Added.Append(GUID, dataStr.str());
+    m_Added.Append(GUID, dataStr.str(), reqInFile);
 }
 
 void CLogFailSafe::AddACK(const char* GUID)
 {
-    m_Cleared.Append(GUID, "");
+    m_Cleared.Append(GUID, "", nullptr);
 
     CriticalBlock b(m_critSec);
     GuidMap::iterator it = m_PendingLogs.find(GUID);

+ 4 - 4
esp/logging/logginglib/LogFailSafe.hpp

@@ -32,8 +32,8 @@ const char* const DefaultFailSafeLogsDir = "./FailSafeLogs";
 
 interface ILogFailSafe : IInterface
 {
-    virtual void Add(const char*, const StringBuffer& strContents)=0;//
-    virtual void Add(const char*,IInterface& pIn)=0;
+    virtual void Add(const char*, const StringBuffer& strContents, CLogRequestInFile* reqInFile)=0;//
+    virtual void Add(const char*,IInterface& pIn, CLogRequestInFile* reqInFile)=0;
     virtual StringBuffer& GenerateGUID(StringBuffer& GUID,const char* seed="") = 0;
     virtual void AddACK(const char* GUID)=0;
     virtual void RollCurrentLog()=0;
@@ -83,8 +83,8 @@ public:
 
     virtual ~CLogFailSafe();
     StringBuffer& GenerateGUID(StringBuffer& GUID,const char* seed="");
-    virtual void Add(const char*, const StringBuffer& strContents);//
-    virtual void Add(const char*,IInterface& pIn);
+    virtual void Add(const char*, const StringBuffer& strContents, CLogRequestInFile* reqInFile);//
+    virtual void Add(const char*,IInterface& pIn, CLogRequestInFile* reqInFile);
     virtual void AddACK(const char* GUID);
     virtual void RollCurrentLog();
     virtual void RollOldLogs();

+ 10 - 3
esp/logging/logginglib/LogSerializer.cpp

@@ -70,7 +70,7 @@ CLogSerializer::~CLogSerializer()
     Close();
 }
 
-void CLogSerializer::Append(const char* GUID, const char* Data)
+void CLogSerializer::Append(const char* GUID, const char* Data, CLogRequestInFile* reqInFile)
 {
     StringBuffer toWrite,size;
 
@@ -84,9 +84,16 @@ void CLogSerializer::Append(const char* GUID, const char* Data)
 
     //optimize
     CriticalBlock b(crit);
+    unsigned len = toWrite.length();
+    if (reqInFile)
+    {
+        reqInFile->setFileName(m_file->queryFilename());
+        reqInFile->setPos(m_file->size());
+        reqInFile->setSize(len);
+    }
     m_ItemCount++;
-    fileSize += toWrite.length();
-    m_bytesWritten += m_fileio->write(m_bytesWritten, toWrite.length(), toWrite.str());
+    fileSize += len;
+    m_bytesWritten += m_fileio->write(m_bytesWritten, len, toWrite.str());
 }
 
 void CLogSerializer::Remove(const char* GUID)

+ 25 - 1
esp/logging/logginglib/LogSerializer.hpp

@@ -29,6 +29,30 @@
 typedef std::set<std::string> GuidSet;//
 typedef std::map<std::string, std::string> GuidMap;
 
+class CLogRequestInFile : public CSimpleInterface
+{
+    StringAttr fileName;
+    offset_t pos;
+    unsigned size;
+    StringAttr GUID;
+    StringAttr option;
+public:
+    IMPLEMENT_IINTERFACE_USING(CSimpleInterface);
+
+    CLogRequestInFile() { };
+
+    const char* getFileName() { return fileName.get(); };
+    void setFileName(const char* _fileName) { fileName.set(_fileName); };
+    const char* getGUID() { return GUID.get(); };
+    void setGUID(const char* _GUID) { GUID.set(_GUID); };
+    const char* getOption() { return option.get(); };
+    void setOption(const char* _option) { option.set(_option); };
+    const offset_t getPos() { return pos; };
+    void setPos(offset_t _pos) { pos = _pos; };
+    const unsigned getSize() { return size; };
+    void setSize(unsigned _size) { size = _size; };
+};
+
 class CLogSerializer : public CInterface
 {
     __int64 m_bytesWritten;
@@ -54,7 +78,7 @@ public:
     void Close();
     void Remove();
     void Rollover(const char* ClosedPrefix);
-    void Append(const char* GUID, const char* Data);
+    void Append(const char* GUID, const char* Data, CLogRequestInFile* reqInFile);
     void Remove(const char* GUID);
     virtual void SplitRecord(StringBuffer& FullStr, StringBuffer& GUID, StringBuffer& Cache){}
     static void splitLogRecord(MemoryBuffer& rawdata,StringBuffer& GUID, StringBuffer& data);//

+ 121 - 0
esp/logging/logginglib/compressutil.cpp

@@ -0,0 +1,121 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2019 HPCC Systems®.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+#include "compressutil.hpp"
+
+#include "jlzw.hpp"
+
+size32_t LZWCompress(const void* src, size32_t srcSz, void* dest, size32_t destSz, size32_t threshold)
+{
+    assertex(destSz>=srcSz+sizeof(size32_t));
+    if (srcSz>=threshold)
+    {
+        Owned<ICompressor> compressor = createLZWCompressor();
+        compressor->open((byte*)dest + sizeof(size32_t), srcSz * 4 / 5);
+        if(compressor->write(src, srcSz)==srcSz)
+        {
+            compressor->close();
+            memcpy(dest, &srcSz, sizeof(size32_t)); 
+            return compressor->buflen() + sizeof(size32_t);
+        }
+    }
+    memcpy((byte*)dest + sizeof(size32_t), src, srcSz);
+    memset(dest, 0, sizeof(size32_t));
+    return srcSz + sizeof(size32_t);
+}
+
+
+size32_t LZWCompress(const void* src, size32_t srcSz, MemoryBuffer& dest, size32_t threshold)
+{
+    size32_t prev = dest.length();
+    size32_t dSz = srcSz + sizeof(size32_t);
+    void* d = dest.reserve(dSz);
+    size32_t ret = LZWCompress(src, srcSz, d, dSz, threshold);
+    dest.setLength(prev+ret);
+    return ret;
+}
+
+size32_t LZWCompress(const void* src, size32_t srcSz, StringBuffer& dest, size32_t threshold)
+{
+    size32_t prev = dest.length();
+    size32_t dSz = srcSz + sizeof(size32_t);
+    void* d = dest.reserve(dSz);
+    size32_t ret = LZWCompress(src, srcSz, d, dSz, threshold);
+    dest.setLength(prev+ret);
+    return ret;
+}
+
+size32_t LZWCompress(MemoryBuffer& src, MemoryBuffer& dest, size32_t threshold)
+{
+    return LZWCompress((const void*)src.toByteArray(), src.length(), dest, threshold);
+}
+
+size32_t LZWExpand(const void* src, size32_t srcSz, void* dest, size32_t destSz)
+{
+    size32_t ret;
+    memcpy(&ret, src, sizeof(size32_t));
+    byte* data = (byte*)src+sizeof(size32_t);
+    if(ret)     // compressed
+    {
+        Owned<IExpander> expander = createLZWExpander();
+        assertex(destSz >= ret);
+        expander->init(data);
+        expander->expand(dest);
+    }
+    else
+    {
+        ret = srcSz - sizeof(size32_t);
+        assertex(destSz >= ret);
+        memcpy(dest, data, ret);
+    }
+    return ret;
+}
+
+size32_t LZWExpand(const void* src, size32_t srcSz, StringBuffer& dest)
+{
+    size32_t sz;
+    memcpy(&sz, src, sizeof(size32_t));
+    size32_t bufSz = (sz == 0) ? (srcSz-sizeof(size32_t)) : sz;
+    void* buf = dest.reserve(bufSz);
+    return LZWExpand(src, srcSz, buf, bufSz); 
+}
+
+size32_t LZWExpand(const void* src, size32_t srcSz, MemoryBuffer& dest)
+{
+    size32_t sz;
+    memcpy(&sz, src, sizeof(size32_t));
+    size32_t bufSz = (sz == 0) ? (srcSz-sizeof(size32_t)) : sz;
+    void* buf = dest.reserve(bufSz);
+    return LZWExpand(src, srcSz, buf, bufSz); 
+}
+
+size32_t LZWExpand(MemoryBuffer& src, MemoryBuffer& dest)
+{
+    size32_t len = src.remaining();
+    const void* pSrc = src.readDirect(len);
+    return LZWExpand(pSrc, len, dest);
+}
+
+
+size32_t LZWExpend(const void* src, size32_t srcSz, CLargeMemoryAllocator& mem)
+{
+    size32_t sz;
+    memcpy(&sz, src, sizeof(size32_t));
+    size32_t bufSz = (sz == 0) ? (srcSz-sizeof(size32_t)) : sz;
+    byte* buf = mem.alloc(bufSz);
+    return LZWExpand(src, srcSz, buf, bufSz); 
+}

+ 45 - 0
esp/logging/logginglib/compressutil.hpp

@@ -0,0 +1,45 @@
+/*##############################################################################
+
+    HPCC SYSTEMS software Copyright (C) 2019 HPCC Systems®.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+############################################################################## */
+
+
+#ifndef _compressutil_ipp
+#define _compressutil_ipp
+
+#include "jlib.hpp"
+#include "jbuff.hpp"
+#include "loggingcommon.hpp"
+
+/*
+    Note: The first sizeof(size32_t) bytes of the compressed buffer contain the
+    original (uncompressed) size of the data or 0. If 0, it indicates that
+    buffer is uncompressed - this happens if the data could not be compressed 
+    by a minimum of 80%.
+*/
+
+extern LOGGINGCOMMON_API size32_t LZWCompress(const void* src, size32_t srcSz, void* dest, size32_t destSz, size32_t threshold=0x1000);
+extern LOGGINGCOMMON_API size32_t LZWCompress(const void* src, size32_t srcSz, StringBuffer& dest, size32_t threshold=0x1000);
+extern LOGGINGCOMMON_API size32_t LZWCompress(const void* src, size32_t srcSz, MemoryBuffer& dest, size32_t threshold=0x1000);
+extern LOGGINGCOMMON_API size32_t LZWCompress(MemoryBuffer& src, MemoryBuffer& dest, size32_t threshold=0x1000);
+extern LOGGINGCOMMON_API size32_t LZWExpand(const void* src, size32_t srcSz, void* dest, size32_t destSz);
+extern LOGGINGCOMMON_API size32_t LZWExpand(const void* src, size32_t srcSz, MemoryBuffer& dest);
+extern LOGGINGCOMMON_API size32_t LZWExpand(MemoryBuffer& src, MemoryBuffer& dest);
+extern LOGGINGCOMMON_API size32_t LZWExpand(const void* src, size32_t srcSz, CLargeMemoryAllocator& mem);
+extern LOGGINGCOMMON_API size32_t LZWExpand(const void* src, size32_t srcSz, StringBuffer& dest);
+
+
+#endif
+

+ 19 - 7
esp/logging/logginglib/loggingagentbase.cpp

@@ -158,7 +158,7 @@ IEspUpdateLogRequestWrap* CLogContentFilter::filterLogContent(IEspUpdateLogReque
     Owned<IPropertyTree> updateLogRequestTree = createPTree("UpdateLogRequest");
 
     StringBuffer source;
-    if (groupFilters.length() < 1)
+    if (logBackEndReq && logBackEndResp && groupFilters.length() < 1)
     {//No filter
         if (logRequestTree)
         {
@@ -233,7 +233,8 @@ IEspUpdateLogRequestWrap* CLogContentFilter::filterLogContent(IEspUpdateLogReque
         }
         else
         {
-            for (unsigned group = 0; group < ESPLCGBackEndResp; group++)
+            //Both ESPLCGBackEndReq and ESPLCGBackEndResp are handled after this loop.
+            for (unsigned group = 0; group < ESPLCGBackEndReq; group++)
             {
                 Owned<IPropertyTree> originalContentTree;
                 if (group == ESPLCGESPContext)
@@ -261,24 +262,35 @@ IEspUpdateLogRequestWrap* CLogContentFilter::filterLogContent(IEspUpdateLogReque
                 if (!originalContentTree)
                     continue;
 
-                IPropertyTree* newContentTree = ensurePTree(logContentTree, espLogContentGroupNames[group]);
-                bool hasFilters = false;
+                bool foundGroupFilters  = false;
                 ForEachItemIn(i, groupFilters)
                 {
                     CESPLogContentGroupFilters& filtersGroup = groupFilters.item(i);
                     if (filtersGroup.getGroup() == group)
                     {
+                        IPropertyTree* newContentTree = ensurePTree(logContentTree, espLogContentGroupNames[group]);
                         if (group != ESPLCGESPContext)//For non ESPLCGESPContext, we want to keep the root of original tree.
                             newContentTree = ensurePTree(newContentTree, originalContentTree->queryName());
                         filterLogContentTree(filtersGroup.getFilters(), originalContentTree, newContentTree, logContentEmpty);
-                        hasFilters =  true;
+                        foundGroupFilters  =  true;
                         break;
                     }
                 }
 
-                if (!hasFilters)
+                if (!foundGroupFilters )
                 {
-                    newContentTree->addPropTree(originalContentTree->queryName(), LINK(originalContentTree));
+                    if (group == ESPLCGESPContext)
+                    {
+                        //The ESPContext tree itself already has the /ESPContext node
+                        //as the top tree node. We should not add another /ESPContext
+                        //node on the top of the ESPContext tree.
+                        logContentTree->addPropTree(originalContentTree->queryName(), LINK(originalContentTree));
+                    }
+                    else
+                    {
+                        IPropertyTree* newContentTree = ensurePTree(logContentTree, espLogContentGroupNames[group]);
+                        newContentTree->addPropTree(originalContentTree->queryName(), LINK(originalContentTree));
+                    }
                     logContentEmpty = false;
                 }
             }

+ 8 - 0
esp/logging/logginglib/loggingagentbase.hpp

@@ -27,6 +27,14 @@
 #include "loggingcommon.hpp"
 #include "LoggingErrors.hpp"
 
+#define LOGREQUEST "LogRequest"
+#define LOGREQUEST_GUID "GUID"
+#define LOGREQUEST_OPTION "option"
+#define LOGCONTENTINFILE "LogContentInFile"
+#define LOGCONTENTINFILE_FILENAME "FileName"
+#define LOGCONTENTINFILE_FILEPOS "Pos"
+#define LOGCONTENTINFILE_FILESIZE "Size"
+
 enum ESPLogContentGroup
 {
     ESPLCGESPContext = 0,

+ 2 - 2
esp/logging/logginglib/logthread.cpp

@@ -146,7 +146,7 @@ bool CLogThread::enqueue(IEspUpdateLogRequestWrap* logRequest)
         logFailSafe->GenerateGUID(GUID, NULL);
         logRequest->setGUID(GUID.str());
         if (serializeLogRequestContent(logRequest, reqBuf))
-            logFailSafe->Add(GUID, reqBuf.str());
+            logFailSafe->Add(GUID, reqBuf.str(), nullptr);
         ESPLOG(LogNormal, "LThread:addToFailSafe: %dms\n", msTick() -  startTime);
     }
 
@@ -286,7 +286,7 @@ void CLogThread::checkRollOver()
             StringBuffer reqBuf;
             const char* GUID = pEspRequest->getGUID();
             if(GUID && *GUID && serializeLogRequestContent(pEspRequest, reqBuf))
-                logFailSafe->Add(GUID, reqBuf.str());
+                logFailSafe->Add(GUID, reqBuf.str(), nullptr);
         }
         ESPLOG(LogNormal, "LThread:AddFailSafe: %dms\n", msTick() -  startTime);
     }

+ 67 - 0
esp/logging/loggingmanager/loggingmanager.cpp

@@ -18,6 +18,7 @@
 #include "LoggingErrors.hpp"
 #include "loggingcommon.hpp"
 #include "loggingmanager.hpp"
+#include "compressutil.hpp"
 
 CLoggingManager::~CLoggingManager(void)
 {
@@ -39,6 +40,13 @@ bool CLoggingManager::init(IPropertyTree* cfg, const char* service)
         return false;
     }
 
+    oneTankFile = cfg->getPropBool("FailSafe");
+    if (oneTankFile)
+    {
+        logFailSafe.setown(createFailSafeLogger(cfg, service, cfg->queryProp("@name")));
+        logContentFilter.readAllLogFilters(cfg);
+    }
+
     Owned<IPTreeIterator> loggingAgentSettings = cfg->getElements("LogAgent");
     ForEach(*loggingAgentSettings)
     {
@@ -218,6 +226,15 @@ bool CLoggingManager::updateLog(IEspContext* espContext, IEspUpdateLogRequestWra
     {
         if (espContext)
             espContext->addTraceSummaryTimeStamp(LogMin, "LMgr:startQLog");
+
+        if (oneTankFile)
+        {
+            Owned<CLogRequestInFile> reqInFile = new CLogRequestInFile();
+            if (!saveToTankFile(req, reqInFile))
+                ERRLOG("LoggingManager: failed in saveToTankFile().");
+            //The reqInFile may be used for passing information to log agents in another PR.
+        }
+
         for (unsigned int x = 0; x < loggingAgentThreads.size(); x++)
         {
             IUpdateLogThread* loggingThread = loggingAgentThreads[x];
@@ -242,6 +259,56 @@ bool CLoggingManager::updateLog(IEspContext* espContext, IEspUpdateLogRequestWra
     return bRet;
 }
 
+bool CLoggingManager::saveToTankFile(IEspUpdateLogRequestWrap& logRequest, CLogRequestInFile* reqInFile)
+{
+    if (!logFailSafe.get())
+    {
+        ERRLOG("CLoggingManager::saveToTankFile: logFailSafe not configured.");
+        return false;
+    }
+
+    unsigned startTime = (getEspLogLevel()>=LogNormal) ? msTick() : 0;
+
+    StringBuffer GUID;
+    logFailSafe->GenerateGUID(GUID, NULL);
+    reqInFile->setGUID(GUID);
+    reqInFile->setOption(logRequest.getOption());
+
+    StringBuffer reqBuf;
+    Owned<IEspUpdateLogRequestWrap> logRequestFiltered = logContentFilter.filterLogContent(&logRequest);
+    if (!serializeLogRequestContent(logRequestFiltered, GUID, reqBuf))
+    {
+        ERRLOG("CLoggingManager::saveToTankFile: failed in serializeLogRequestContent().");
+        return false;
+    }
+
+    logFailSafe->AddACK(GUID);//Ack this logging request since the task will be done as soon as the next line is called.
+    logFailSafe->Add(GUID, reqBuf, reqInFile);
+
+    ESPLOG(LogNormal, "LThread:saveToTankFile: %dms\n", msTick() - startTime);
+    return true;
+}
+
+unsigned CLoggingManager::serializeLogRequestContent(IEspUpdateLogRequestWrap* request, const char* GUID, StringBuffer& logData)
+{
+    appendXMLTag(logData, LOGREQUEST_GUID, GUID);
+
+    const char* option = request->getOption();
+    if (!isEmptyString(option))
+        appendXMLTag(logData, LOGREQUEST_OPTION, option);
+
+    appendXMLOpenTag(logData, LOGREQUEST);
+
+    const char* logRequest = request->getUpdateLogRequest();
+    MemoryBuffer memBuf;
+    LZWCompress(logRequest, strlen(logRequest), memBuf, 0x100);
+    JBASE64_Encode(memBuf.toByteArray(), memBuf.length(), logData);
+
+    appendXMLCloseTag(logData, LOGREQUEST);
+
+    return logData.length();
+}
+
 bool CLoggingManager::getTransactionSeed(StringBuffer& transactionSeed, StringBuffer& status)
 {
     if (!initialized)

+ 6 - 1
esp/logging/loggingmanager/loggingmanager.hpp

@@ -24,6 +24,7 @@
 #include "loggingagentbase.hpp"
 #include "logthread.hpp"
 #include "loggingmanager.h"
+#include "LogFailSafe.hpp"
 
 #ifdef LOGGINGMANAGER_EXPORTS
     #define LOGGINGMANAGER_API DECL_EXPORT
@@ -75,10 +76,14 @@ class CLoggingManager : implements ILoggingManager, public CInterface
 {
     typedef std::vector<IUpdateLogThread*> LOGGING_AGENTTHREADS;
     LOGGING_AGENTTHREADS  loggingAgentThreads;
-    bool initialized;
+    bool oneTankFile = false, initialized;
+    Owned<ILogFailSafe> logFailSafe;
+    CLogContentFilter logContentFilter;
 
     IEspLogAgent* loadLoggingAgent(const char* name, const char* dll, const char* type, IPropertyTree* cfg);
     bool updateLogImpl(IEspUpdateLogRequestWrap& req, IEspUpdateLogResponse& resp);
+    bool saveToTankFile(IEspUpdateLogRequestWrap& req, CLogRequestInFile* reqInFile);
+    unsigned serializeLogRequestContent(IEspUpdateLogRequestWrap* request, const char* GUID, StringBuffer& logData);
 
     bool updateLog(IEspContext* espContext, IEspUpdateLogRequestWrap& req, IEspUpdateLogResponse& resp, StringBuffer& status);
     bool updateLog(IEspContext* espContext, const char* option, IPropertyTree* userContext, IPropertyTree* userRequest,

+ 15 - 0
initfiles/componentfiles/configxml/@temp/esp_service_DynamicESDL.xsl

@@ -71,6 +71,21 @@
                 </xsl:if>
 
                 <LoggingManager name="{$managerNode/@name}">
+                    <xsl:if test="string($managerNode/@FailSafe) != ''">
+                        <FailSafe><xsl:value-of select="$managerNode/@FailSafe"/></FailSafe>
+                    </xsl:if>
+                    <xsl:if test="string($managerNode/@FailSafeLogsDir) != ''">
+                        <FailSafeLogsDir><xsl:value-of select="$managerNode/@FailSafeLogsDir"/></FailSafeLogsDir>
+                    </xsl:if>
+                    <xsl:if test="string($managerNode/@SafeRolloverThreshold) != ''">
+                        <SafeRolloverThreshold><xsl:value-of select="$managerNode/@SafeRolloverThreshold"/></SafeRolloverThreshold>
+                    </xsl:if>
+                    <Filters>
+                        <xsl:for-each select="$managerNode/Filter">
+                            <Filter value="{current()/@filter}" type="{current()/@type}"/>
+                        </xsl:for-each>
+                    </Filters>
+
                     <xsl:for-each select="$managerNode/ESPLoggingAgent">
                         <xsl:variable name="agentName" select="@ESPLoggingAgent"/>
                         <xsl:variable name="espLoggingAgentNode" select="/Environment/Software/ESPLoggingAgent[@name=$agentName]"/>

+ 36 - 0
initfiles/componentfiles/configxml/loggingmanager.xsd

@@ -63,6 +63,42 @@
         </xs:element>
      </xs:sequence>
 
+     <xs:sequence>
+        <xs:element name="Filter" minOccurs="0" maxOccurs="unbounded">
+          <xs:annotation>
+            <xs:appinfo>
+              <title>Filters</title>
+            </xs:appinfo>
+          </xs:annotation>
+          <xs:complexType>
+            <xs:attribute name="filter" type="relativePath" use="required">
+              <xs:annotation>
+                <xs:appinfo>
+                  <colIndex>1</colIndex>
+                </xs:appinfo>
+              </xs:annotation>
+            </xs:attribute>
+            <xs:attribute name="type" use="optional">
+              <xs:annotation>
+                <xs:appinfo>
+                  <colIndex>2</colIndex>
+                </xs:appinfo>
+              </xs:annotation>
+              <xs:simpleType>
+                <xs:restriction base="xs:string">
+                  <xs:enumeration value="ESPContext"/>
+                  <xs:enumeration value="UserContext"/>
+                  <xs:enumeration value="UserRequest"/>
+                  <xs:enumeration value="UserResponse"/>
+                  <xs:enumeration value="BackEndRequest"/>
+                  <xs:enumeration value="BackEndResponse"/>
+                 </xs:restriction>
+               </xs:simpleType>              
+            </xs:attribute>
+          </xs:complexType>
+        </xs:element>
+      </xs:sequence>
+
     </xs:complexType>
   </xs:element>
 </xs:schema>