loggingagentbase.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2016 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "LoggingErrors.hpp"
  14. #include "loggingagentbase.hpp"
  15. static const char* const defaultTransactionTable = "transactions";
  16. static const char* const defaultTransactionAppName = "accounting_log";
  17. static const char* const defaultLoggingTransactionAppName = "logging_transaction";
  18. void CLogContentFilter::readAllLogFilters(IPropertyTree* cfg)
  19. {
  20. bool groupFilterRead = false;
  21. VStringBuffer xpath("Filters/Filter[@type='%s']", espLogContentGroupNames[ESPLCGBackEndResp]);
  22. IPropertyTree* filter = cfg->queryBranch(xpath.str());
  23. if (filter && filter->hasProp("@value"))
  24. {
  25. logBackEndResp = filter->getPropBool("@value");
  26. groupFilterRead = true;
  27. }
  28. xpath.setf("Filters/Filter[@type='%s']", espLogContentGroupNames[ESPLCGBackEndReq]);
  29. filter = cfg->queryBranch(xpath.str());
  30. if (filter && filter->hasProp("@value"))
  31. {
  32. logBackEndReq = filter->getPropBool("@value");
  33. groupFilterRead = true;
  34. }
  35. for (unsigned i = 0; i < ESPLCGBackEndReq; i++)
  36. {
  37. if (readLogFilters(cfg, i))
  38. groupFilterRead = true;
  39. }
  40. if (!groupFilterRead)
  41. {
  42. groupFilters.clear();
  43. readLogFilters(cfg, ESPLCGAll);
  44. }
  45. }
  46. bool CLogContentFilter::readLogFilters(IPropertyTree* cfg, unsigned groupID)
  47. {
  48. Owned<CESPLogContentGroupFilters> espLogContentGroupFilters = new CESPLogContentGroupFilters((ESPLogContentGroup) groupID);
  49. StringBuffer xpath;
  50. if (groupID != ESPLCGAll)
  51. xpath.appendf("Filters/Filter[@type='%s']", espLogContentGroupNames[groupID]);
  52. else
  53. xpath.append("Filters/Filter");
  54. Owned<IPropertyTreeIterator> filters = cfg->getElements(xpath.str());
  55. ForEach(*filters)
  56. {
  57. IPropertyTree &filter = filters->query();
  58. StringBuffer value(filter.queryProp("@value"));
  59. if (!value.length())
  60. continue;
  61. //clean "//"
  62. unsigned idx = value.length()-1;
  63. while (idx)
  64. {
  65. if ((value.charAt(idx-1) == '/') && (value.charAt(idx) == '/'))
  66. value.remove(idx, 1);
  67. idx--;
  68. }
  69. //clean "/*" at the end
  70. while ((value.length() > 1) && (value.charAt(value.length()-2) == '/') && (value.charAt(value.length()-1) == '*'))
  71. value.setLength(value.length() - 2);
  72. if (value.length() && !streq(value.str(), "*") && !streq(value.str(), "/") && !streq(value.str(), "*/"))
  73. {
  74. espLogContentGroupFilters->addFilter(value.str());
  75. }
  76. else
  77. {
  78. espLogContentGroupFilters->clearFilters();
  79. break;
  80. }
  81. }
  82. bool hasFilter = espLogContentGroupFilters->getFilterCount() > 0;
  83. if (hasFilter)
  84. groupFilters.append(*espLogContentGroupFilters.getClear());
  85. return hasFilter;
  86. }
  87. void CLogContentFilter::addLogContentBranch(StringArray& branchNames, IPropertyTree* contentToLogBranch, IPropertyTree* updateLogRequestTree)
  88. {
  89. IPropertyTree* pTree = updateLogRequestTree;
  90. unsigned numOfBranchNames = branchNames.length();
  91. unsigned i = 0;
  92. while (i < numOfBranchNames)
  93. {
  94. const char* branchName = branchNames.item(i);
  95. if (branchName && *branchName)
  96. pTree = ensurePTree(pTree, branchName);
  97. i++;
  98. }
  99. pTree->addPropTree(contentToLogBranch->queryName(), LINK(contentToLogBranch));
  100. }
  101. void CLogContentFilter::filterAndAddLogContentBranch(StringArray& branchNamesInFilter, unsigned idx,
  102. StringArray& branchNamesInLogContent, IPropertyTree* originalLogContentBranch, IPropertyTree* updateLogRequestTree, bool& logContentEmpty)
  103. {
  104. Owned<IPropertyTreeIterator> contentItr = originalLogContentBranch->getElements(branchNamesInFilter.item(idx));
  105. ForEach(*contentItr)
  106. {
  107. IPropertyTree& contentToLogBranch = contentItr->query();
  108. if (idx == branchNamesInFilter.length() - 1)
  109. {
  110. addLogContentBranch(branchNamesInLogContent, &contentToLogBranch, updateLogRequestTree);
  111. logContentEmpty = false;
  112. }
  113. else
  114. {
  115. branchNamesInLogContent.append(contentToLogBranch.queryName());
  116. filterAndAddLogContentBranch(branchNamesInFilter, idx+1, branchNamesInLogContent, &contentToLogBranch,
  117. updateLogRequestTree, logContentEmpty);
  118. branchNamesInLogContent.remove(branchNamesInLogContent.length() - 1);
  119. }
  120. }
  121. }
  122. void CLogContentFilter::filterLogContentTree(StringArray& filters, IPropertyTree* originalContentTree, IPropertyTree* newLogContentTree, bool& logContentEmpty)
  123. {
  124. ForEachItemIn(i, filters)
  125. {
  126. const char* logContentFilter = filters.item(i);
  127. if(!logContentFilter || !*logContentFilter)
  128. continue;
  129. StringArray branchNamesInFilter, branchNamesInLogContent;
  130. branchNamesInFilter.appendListUniq(logContentFilter, "/");
  131. filterAndAddLogContentBranch(branchNamesInFilter, 0, branchNamesInLogContent, originalContentTree, newLogContentTree, logContentEmpty);
  132. }
  133. }
  134. IEspUpdateLogRequestWrap* CLogContentFilter::filterLogContent(IEspUpdateLogRequestWrap* req)
  135. {
  136. const char* logContent = req->getUpdateLogRequest();
  137. Owned<IPropertyTree> logRequestTree = req->getLogRequestTree();
  138. Owned<IPropertyTree> updateLogRequestTree = createPTree("UpdateLogRequest");
  139. StringBuffer source;
  140. if (logBackEndReq && logBackEndResp && groupFilters.length() < 1)
  141. {//No filter
  142. if (logRequestTree)
  143. {
  144. updateLogRequestTree->addPropTree(logRequestTree->queryName(), LINK(logRequestTree));
  145. }
  146. else if (logContent && *logContent)
  147. {
  148. Owned<IPropertyTree> pTree = createPTreeFromXMLString(logContent);
  149. source = pTree->queryProp("Source");
  150. updateLogRequestTree->addPropTree(pTree->queryName(), LINK(pTree));
  151. }
  152. else
  153. {
  154. Owned<IPropertyTree> espContext = req->getESPContext();
  155. Owned<IPropertyTree> userContext = req->getUserContext();
  156. Owned<IPropertyTree> userRequest = req->getUserRequest();
  157. const char* userResp = req->getUserResponse();
  158. const char* logDatasets = req->getLogDatasets();
  159. const char* backEndReq = req->getBackEndRequest();
  160. const char* backEndResp = req->getBackEndResponse();
  161. if (!espContext && !userContext && !userRequest && (!userResp || !*userResp) && (!backEndResp || !*backEndResp))
  162. throw MakeStringException(EspLoggingErrors::UpdateLogFailed, "Failed to read log content");
  163. source = userContext->queryProp("Source");
  164. StringBuffer espContextXML, userContextXML, userRequestXML;
  165. IPropertyTree* logContentTree = ensurePTree(updateLogRequestTree, "LogContent");
  166. if (espContext)
  167. {
  168. logContentTree->addPropTree(espContext->queryName(), LINK(espContext));
  169. }
  170. if (userContext)
  171. {
  172. IPropertyTree* pTree = ensurePTree(logContentTree, espLogContentGroupNames[ESPLCGUserContext]);
  173. pTree->addPropTree(userContext->queryName(), LINK(userContext));
  174. }
  175. if (userRequest)
  176. {
  177. IPropertyTree* pTree = ensurePTree(logContentTree, espLogContentGroupNames[ESPLCGUserReq]);
  178. pTree->addPropTree(userRequest->queryName(), LINK(userRequest));
  179. }
  180. if (!isEmptyString(userResp))
  181. {
  182. IPropertyTree* pTree = ensurePTree(logContentTree, espLogContentGroupNames[ESPLCGUserResp]);
  183. Owned<IPropertyTree> userRespTree = createPTreeFromXMLString(userResp);
  184. pTree->addPropTree(userRespTree->queryName(), LINK(userRespTree));
  185. }
  186. if (!isEmptyString(logDatasets))
  187. {
  188. IPropertyTree* pTree = ensurePTree(logContentTree, espLogContentGroupNames[ESPLCGLogDatasets]);
  189. Owned<IPropertyTree> logDatasetTree = createPTreeFromXMLString(logDatasets);
  190. pTree->addPropTree(logDatasetTree->queryName(), LINK(logDatasetTree));
  191. }
  192. if (!isEmptyString(backEndReq))
  193. logContentTree->addProp(espLogContentGroupNames[ESPLCGBackEndReq], backEndReq);
  194. if (!isEmptyString(backEndResp))
  195. logContentTree->addProp(espLogContentGroupNames[ESPLCGBackEndResp], backEndResp);
  196. }
  197. }
  198. else
  199. {
  200. bool logContentEmpty = true;
  201. IPropertyTree* logContentTree = ensurePTree(updateLogRequestTree, "LogContent");
  202. if (logRequestTree)
  203. {
  204. filterLogContentTree(groupFilters.item(0).getFilters(), logRequestTree, logContentTree, logContentEmpty);
  205. }
  206. else if (logContent && *logContent)
  207. {
  208. Owned<IPropertyTree> originalContentTree = createPTreeFromXMLString(logContent);
  209. source = originalContentTree->queryProp("Source");
  210. filterLogContentTree(groupFilters.item(0).getFilters(), originalContentTree, logContentTree, logContentEmpty);
  211. }
  212. else
  213. {
  214. //Both ESPLCGBackEndReq and ESPLCGBackEndResp are handled after this loop.
  215. for (unsigned group = 0; group < ESPLCGBackEndReq; group++)
  216. {
  217. Owned<IPropertyTree> originalContentTree;
  218. if (group == ESPLCGESPContext)
  219. originalContentTree.setown(req->getESPContext());
  220. else if (group == ESPLCGUserContext)
  221. {
  222. originalContentTree.setown(req->getUserContext());
  223. source = originalContentTree->queryProp("Source");
  224. }
  225. else if (group == ESPLCGUserReq)
  226. originalContentTree.setown(req->getUserRequest());
  227. else if (group == ESPLCGLogDatasets)
  228. {
  229. const char* logDatasets = req->getLogDatasets();
  230. if (logDatasets && *logDatasets)
  231. originalContentTree.setown(createPTreeFromXMLString(logDatasets));
  232. }
  233. else //group = ESPLCGUserResp
  234. {
  235. const char* resp = req->getUserResponse();
  236. if (!resp || !*resp)
  237. continue;
  238. originalContentTree.setown(createPTreeFromXMLString(resp));
  239. }
  240. if (!originalContentTree)
  241. continue;
  242. bool foundGroupFilters = false;
  243. ForEachItemIn(i, groupFilters)
  244. {
  245. CESPLogContentGroupFilters& filtersGroup = groupFilters.item(i);
  246. if (filtersGroup.getGroup() == group)
  247. {
  248. IPropertyTree* newContentTree = ensurePTree(logContentTree, espLogContentGroupNames[group]);
  249. if (group != ESPLCGESPContext)//For non ESPLCGESPContext, we want to keep the root of original tree.
  250. newContentTree = ensurePTree(newContentTree, originalContentTree->queryName());
  251. filterLogContentTree(filtersGroup.getFilters(), originalContentTree, newContentTree, logContentEmpty);
  252. foundGroupFilters = true;
  253. break;
  254. }
  255. }
  256. if (!foundGroupFilters )
  257. {
  258. if (group == ESPLCGESPContext)
  259. {
  260. //The ESPContext tree itself already has the /ESPContext node
  261. //as the top tree node. We should not add another /ESPContext
  262. //node on the top of the ESPContext tree.
  263. logContentTree->addPropTree(originalContentTree->queryName(), LINK(originalContentTree));
  264. }
  265. else
  266. {
  267. IPropertyTree* newContentTree = ensurePTree(logContentTree, espLogContentGroupNames[group]);
  268. newContentTree->addPropTree(originalContentTree->queryName(), LINK(originalContentTree));
  269. }
  270. logContentEmpty = false;
  271. }
  272. }
  273. if (logBackEndReq)
  274. {
  275. const char* request = req->getBackEndRequest();
  276. if (!isEmptyString(request))
  277. {
  278. logContentTree->addProp(espLogContentGroupNames[ESPLCGBackEndReq], request);
  279. logContentEmpty = false;
  280. }
  281. }
  282. if (logBackEndResp)
  283. {
  284. const char* resp = req->getBackEndResponse();
  285. if (resp && *resp)
  286. {
  287. logContentTree->addProp(espLogContentGroupNames[ESPLCGBackEndResp], resp);
  288. logContentEmpty = false;
  289. }
  290. }
  291. }
  292. if (logContentEmpty)
  293. throw MakeStringException(EspLoggingErrors::UpdateLogFailed, "Failed to read log content");
  294. }
  295. if (!source.isEmpty())
  296. updateLogRequestTree->addProp("LogContent/Source", source.str());
  297. const char* option = req->getOption();
  298. if (option && *option)
  299. updateLogRequestTree->addProp("Option", option);
  300. StringBuffer updateLogRequestXML;
  301. toXML(updateLogRequestTree, updateLogRequestXML);
  302. ESPLOG(LogMax, "filtered content and option: <%s>", updateLogRequestXML.str());
  303. return new CUpdateLogRequestWrap(req->getGUID(), req->getOption(), updateLogRequestXML.str());
  304. }
  305. void CDBLogAgentBase::readDBCfg(IPropertyTree* cfg, StringBuffer& server, StringBuffer& dbUser, StringBuffer& dbPassword)
  306. {
  307. ensureInputString(cfg->queryProp("@server"), true, server, -1, "Database server required");
  308. ensureInputString(cfg->queryProp("@dbName"), true, defaultDB, -1, "Database name required");
  309. transactionTable.set(cfg->hasProp("@dbTableName") ? cfg->queryProp("@dbTableName") : defaultTransactionTable);
  310. dbUser.set(cfg->queryProp("@dbUser"));
  311. const char* encodedPassword = cfg->queryProp("@dbPassWord");
  312. if(encodedPassword && *encodedPassword)
  313. decrypt(dbPassword, encodedPassword);
  314. }
  315. void CDBLogAgentBase::readTransactionCfg(IPropertyTree* cfg)
  316. {
  317. //defaultTransactionApp: if no APP name is given, which APP name (TableName) should be used to get a transaction seed?
  318. //loggingTransactionApp: the TableName used to get a transaction seed for this logging agent
  319. defaultTransactionApp.set(cfg->hasProp("defaultTransaction") ? cfg->queryProp("defaultTransaction") : defaultTransactionAppName);
  320. loggingTransactionApp.set(cfg->hasProp("loggingTransaction") ? cfg->queryProp("loggingTransaction") : defaultLoggingTransactionAppName);
  321. loggingTransactionCount = 0;
  322. }
  323. bool CDBLogAgentBase::getTransactionSeed(IEspGetTransactionSeedRequest& req, IEspGetTransactionSeedResponse& resp)
  324. {
  325. if (!hasService(LGSTGetTransactionSeed))
  326. throw MakeStringException(EspLoggingErrors::GetTransactionSeedFailed, "%s: no getTransactionSeed service configured", agentName.get());
  327. bool bRet = false;
  328. StringBuffer appName(req.getApplication());
  329. appName.trim();
  330. if (appName.length() == 0)
  331. appName = defaultTransactionApp.get();
  332. unsigned retry = 1;
  333. while (1)
  334. {
  335. try
  336. {
  337. StringBuffer logSeed;
  338. queryTransactionSeed(appName, logSeed);
  339. if (!logSeed.length())
  340. throw MakeStringException(EspLoggingErrors::GetTransactionSeedFailed, "Failed to get TransactionSeed");
  341. resp.setSeedId(logSeed.str());
  342. resp.setStatusCode(0);
  343. bRet = true;
  344. break;
  345. }
  346. catch (IException* e)
  347. {
  348. StringBuffer errorStr, errorMessage;
  349. errorMessage.append("Failed to get TransactionSeed: error code ").append(e->errorCode()).append(", error message ").append(e->errorMessage(errorStr));
  350. ERRLOG("%s -- try %d", errorMessage.str(), retry);
  351. e->Release();
  352. if (retry < maxTriesGTS)
  353. {
  354. Sleep(retry*3000);
  355. retry++;
  356. }
  357. else
  358. {
  359. resp.setStatusCode(-1);
  360. resp.setStatusMessage(errorMessage.str());
  361. break;
  362. }
  363. }
  364. }
  365. return bRet;
  366. }
  367. bool CDBLogAgentBase::updateLog(IEspUpdateLogRequestWrap& req, IEspUpdateLogResponse& resp)
  368. {
  369. if (!hasService(LGSTUpdateLOG))
  370. throw MakeStringException(EspLoggingErrors::UpdateLogFailed, "%s: no updateLog service configured", agentName.get());
  371. unsigned startTime = (getEspLogLevel()>=LogNormal) ? msTick() : 0;
  372. bool ret = false;
  373. try
  374. {
  375. const char* updateLogReq = req.getUpdateLogRequest();
  376. if (!updateLogReq || !*updateLogReq)
  377. throw MakeStringException(EspLoggingErrors::UpdateLogFailed, "Failed to read log request.");
  378. StringBuffer requestBuf, logDB, logSource;
  379. requestBuf.append("<LogRequest>").append(updateLogReq).append("</LogRequest>");
  380. Owned<IPropertyTree> logRequestTree = createPTreeFromXMLString(requestBuf.length(), requestBuf.str());
  381. if (!logRequestTree)
  382. throw MakeStringException(EspLoggingErrors::UpdateLogFailed, "Failed to read log request.");
  383. CLogGroup* logGroup = checkLogSource(logRequestTree, logSource, logDB);
  384. if (!logGroup)
  385. throw MakeStringException(EspLoggingErrors::UpdateLogFailed, "Log Group %s undefined.", logSource.str());
  386. StringBuffer logID;
  387. getLoggingTransactionID(logID);
  388. CIArrayOf<CLogTable>& logTables = logGroup->getLogTables();
  389. ForEachItemIn(i, logTables)
  390. {
  391. CLogTable& table = logTables.item(i);
  392. StringBuffer updateDBStatement;
  393. if(!buildUpdateLogStatement(logRequestTree, logDB.str(), table, logID, updateDBStatement))
  394. throw MakeStringException(EspLoggingErrors::UpdateLogFailed, "Failed in creating SQL statement.");
  395. ESPLOG(LogNormal, "LAgent UpdateLog BuildStat %d done: %dms\n", i, msTick() - startTime);
  396. ESPLOG(LogMax, "UpdateLog: %s\n", updateDBStatement.str());
  397. executeUpdateLogStatement(updateDBStatement);
  398. ESPLOG(LogNormal, "LAgent UpdateLog ExecStat %d done: %dms\n", i, msTick() - startTime);
  399. }
  400. resp.setStatusCode(0);
  401. ret = true;
  402. }
  403. catch (IException* e)
  404. {
  405. StringBuffer errorStr, errorMessage;
  406. errorMessage.append("Failed to update log: error code ").append(e->errorCode()).append(", error message ").append(e->errorMessage(errorStr));
  407. ERRLOG("%s", errorMessage.str());
  408. e->Release();
  409. resp.setStatusCode(-1);
  410. resp.setStatusMessage(errorMessage.str());
  411. }
  412. ESPLOG(LogNormal, "LAgent UpdateLog total=%dms\n", msTick() - startTime);
  413. return ret;
  414. }
  415. CLogGroup* CDBLogAgentBase::checkLogSource(IPropertyTree* logRequest, StringBuffer& source, StringBuffer& logDB)
  416. {
  417. if (logSourceCount == 0)
  418. {//if no log source is configured, use default Log Group and DB
  419. logDB.set(defaultDB.str());
  420. source.set(defaultLogGroup.get());
  421. return logGroups.getValue(defaultLogGroup.get());
  422. }
  423. source = logRequest->queryProp(logSourcePath.get());
  424. if (source.isEmpty())
  425. throw MakeStringException(EspLoggingErrors::UpdateLogFailed, "Failed to read log Source from request.");
  426. CLogSource* logSource = logSources.getValue(source.str());
  427. if (!logSource)
  428. throw MakeStringException(EspLoggingErrors::UpdateLogFailed, "Log Source %s undefined.", source.str());
  429. logDB.set(logSource->getDBName());
  430. return logGroups.getValue(logSource->getGroupName());
  431. }
  432. void CDBLogAgentBase::getLoggingTransactionID(StringBuffer& id)
  433. {
  434. id.set(loggingTransactionSeed.str()).append("-").append(++loggingTransactionCount);
  435. }
  436. bool CDBLogAgentBase::buildUpdateLogStatement(IPropertyTree* logRequest, const char* logDB,
  437. CLogTable& table, StringBuffer& logID, StringBuffer& updateDBStatement)
  438. {
  439. StringBuffer fields, values;
  440. BoolHash handledFields;
  441. CIArrayOf<CLogField>& logFields = table.getLogFields();
  442. ForEachItemIn(i, logFields) //Go through data items to be logged
  443. {
  444. CLogField& logField = logFields.item(i);
  445. StringBuffer colName(logField.getMapTo());
  446. bool* found = handledFields.getValue(colName.str());
  447. if (found && *found)
  448. continue;
  449. StringBuffer path(logField.getName());
  450. if (path.charAt(path.length() - 1) == ']')
  451. {//Attr filter. Separate the last [] from the path.
  452. const char* pTr = path.str();
  453. const char* ppTr = strrchr(pTr, '[');
  454. if (!ppTr)
  455. continue;
  456. StringBuffer attr;
  457. attr.set(ppTr+1);
  458. attr.setLength(attr.length() - 1);
  459. path.setLength(ppTr - pTr);
  460. StringBuffer colValue;
  461. Owned<IPropertyTreeIterator> itr = logRequest->getElements(path.str());
  462. ForEach(*itr)
  463. {//Log the first valid match just in case more than one matches.
  464. IPropertyTree& ppTree = itr->query();
  465. colValue.set(ppTree.queryProp(attr.str()));
  466. if (colValue.length())
  467. {
  468. addField(logField, colName.str(), colValue, fields, values);
  469. handledFields.setValue(colName.str(), true);
  470. break;
  471. }
  472. }
  473. continue;
  474. }
  475. Owned<IPropertyTreeIterator> itr = logRequest->getElements(path.str());
  476. ForEach(*itr)
  477. {
  478. IPropertyTree& ppTree = itr->query();
  479. StringBuffer colValue;
  480. if (ppTree.hasChildren()) //This is a tree branch.
  481. toXML(&ppTree, colValue);
  482. else
  483. ppTree.getProp(NULL, colValue);
  484. if (colValue.length())
  485. {
  486. addField(logField, colName.str(), colValue, fields, values);
  487. handledFields.setValue(colName.str(), true);
  488. break;
  489. }
  490. }
  491. }
  492. //add any default fields that may be required but not in request.
  493. addMissingFields(logFields, handledFields, fields, values);
  494. if (table.getEnableLogID()) {
  495. appendFieldInfo("log_id", logID, fields, values, true);
  496. }
  497. setUpdateLogStatement(logDB, table.getTableName(), fields.str(), values.str(), updateDBStatement);
  498. return true;
  499. }
  500. void CDBLogAgentBase::appendFieldInfo(const char* field, StringBuffer& value, StringBuffer& fields, StringBuffer& values, bool quoted)
  501. {
  502. if(values.length() != 0)
  503. values.append(',');
  504. if (quoted)
  505. values.append('\'').append(value.length(), value.str()).append('\'');
  506. else
  507. values.append(value.length(), value.str());
  508. if(fields.length() != 0)
  509. fields.append(',');
  510. fields.append(field);
  511. }
  512. void CDBLogAgentBase::addMissingFields(CIArrayOf<CLogField>& logFields, BoolHash& handledFields, StringBuffer& fields, StringBuffer& values)
  513. {
  514. ForEachItemIn(i, logFields) //Go through data items to be logged
  515. {
  516. CLogField& logField = logFields.item(i);
  517. const char* colName = logField.getMapTo();
  518. bool* found = handledFields.getValue(colName);
  519. if (found && *found)
  520. continue;
  521. StringBuffer value(logField.getDefault());
  522. if (!value.isEmpty())
  523. addField(logField, colName, value, fields, values);
  524. }
  525. }
  526. void CDBLogAgentBase::getTransactionID(StringAttrMapping* transFields, StringBuffer& transactionID)
  527. {
  528. //Not implemented
  529. }
  530. IEspUpdateLogRequestWrap* CDBLogAgentBase::filterLogContent(IEspUpdateLogRequestWrap* req)
  531. {
  532. //No filter in CDBSQLLogAgent
  533. return req;
  534. }