123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- /*##############################################################################
- HPCC SYSTEMS software Copyright (C) 2016 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 "LoggingErrors.hpp"
- #include "esploggingservice_esp.ipp"
- #include "loggingagentbase.hpp"
- static const char* const defaultTransactionTable = "transactions";
- static const char* const defaultTransactionAppName = "accounting_log";
- static const char* const defaultLoggingTransactionAppName = "logging_transaction";
- void CDBLogAgentBase::readDBCfg(IPropertyTree* cfg, StringBuffer& server, StringBuffer& dbUser, StringBuffer& dbPassword)
- {
- ensureInputString(cfg->queryProp("@server"), true, server, -1, "Database server required");
- ensureInputString(cfg->queryProp("@dbName"), true, defaultDB, -1, "Database name required");
- transactionTable.set(cfg->hasProp("@dbTableName") ? cfg->queryProp("@dbTableName") : defaultTransactionTable);
- dbUser.set(cfg->queryProp("@dbUser"));
- const char* encodedPassword = cfg->queryProp("@dbPassWord");
- if(encodedPassword && *encodedPassword)
- decrypt(dbPassword, encodedPassword);
- }
- void CDBLogAgentBase::readTransactionCfg(IPropertyTree* cfg)
- {
- //defaultTransactionApp: if no APP name is given, which APP name (TableName) should be used to get a transaction seed?
- //loggingTransactionApp: the TableName used to get a transaction seed for this logging agent
- defaultTransactionApp.set(cfg->hasProp("defaultTransaction") ? cfg->queryProp("defaultTransaction") : defaultTransactionAppName);
- loggingTransactionApp.set(cfg->hasProp("loggingTransaction") ? cfg->queryProp("loggingTransaction") : defaultLoggingTransactionAppName);
- loggingTransactionCount = 0;
- }
- bool CDBLogAgentBase::getTransactionSeed(IEspGetTransactionSeedRequest& req, IEspGetTransactionSeedResponse& resp)
- {
- bool bRet = false;
- StringBuffer appName = req.getApplication();
- appName.trim();
- if (appName.length() == 0)
- appName = defaultTransactionApp.get();
- unsigned retry = 1;
- while (1)
- {
- try
- {
- StringBuffer logSeed;
- queryTransactionSeed(appName, logSeed);
- if (!logSeed.length())
- throw MakeStringException(EspLoggingErrors::GetTransactionSeedFailed, "Failed to get TransactionSeed");
- resp.setSeedId(logSeed.str());
- resp.setStatusCode(0);
- bRet = true;
- break;
- }
- catch (IException* e)
- {
- StringBuffer errorStr, errorMessage;
- errorMessage.append("Failed to get TransactionSeed: error code ").append(e->errorCode()).append(", error message ").append(e->errorMessage(errorStr));
- ERRLOG("%s -- try %d", errorMessage.str(), retry);
- e->Release();
- if (retry < maxTriesGTS)
- {
- Sleep(retry*3000);
- retry++;
- }
- else
- {
- resp.setStatusCode(-1);
- resp.setStatusMessage(errorMessage.str());
- break;
- }
- }
- }
- return bRet;
- }
- bool CDBLogAgentBase::updateLog(IEspUpdateLogRequestWrap& req, IEspUpdateLogResponse& resp)
- {
- unsigned startTime = (getEspLogLevel()>=LogNormal) ? msTick() : 0;
- bool ret = false;
- try
- {
- const char* updateLogReq = req.getUpdateLogRequest();
- if (!updateLogReq || !*updateLogReq)
- throw MakeStringException(EspLoggingErrors::UpdateLogFailed, "Failed to read log request.");
- StringBuffer requestBuf, logDB, logSource;
- requestBuf.append("<LogRequest>").append(updateLogReq).append("</LogRequest>");
- Owned<IPropertyTree> logRequestTree = createPTreeFromXMLString(requestBuf.length(), requestBuf.str());
- if (!logRequestTree)
- throw MakeStringException(EspLoggingErrors::UpdateLogFailed, "Failed to read log request.");
- CLogGroup* logGroup = checkLogSource(logRequestTree, logSource, logDB);
- if (!logGroup)
- throw MakeStringException(EspLoggingErrors::UpdateLogFailed, "Log Group %s undefined.", logSource.str());
- StringBuffer logID;
- getLoggingTransactionID(logID);
- CIArrayOf<CLogTable>& logTables = logGroup->getLogTables();
- ForEachItemIn(i, logTables)
- {
- CLogTable& table = logTables.item(i);
- StringBuffer updateDBStatement;
- if(!buildUpdateLogStatement(logRequestTree, logDB.str(), table, logID, updateDBStatement))
- throw MakeStringException(EspLoggingErrors::UpdateLogFailed, "Failed in creating SQL statement.");
- ESPLOG(LogNormal, "LAgent UpdateLog BuildStat %d done: %dms\n", i, msTick() - startTime);
- ESPLOG(LogMax, "UpdateLog: %s\n", updateDBStatement.str());
- executeUpdateLogStatement(updateDBStatement);
- ESPLOG(LogNormal, "LAgent UpdateLog ExecStat %d done: %dms\n", i, msTick() - startTime);
- }
- resp.setStatusCode(0);
- ret = true;
- }
- catch (IException* e)
- {
- StringBuffer errorStr, errorMessage;
- errorMessage.append("Failed to update log: error code ").append(e->errorCode()).append(", error message ").append(e->errorMessage(errorStr));
- ERRLOG("%s", errorMessage.str());
- e->Release();
- resp.setStatusCode(-1);
- resp.setStatusMessage(errorMessage.str());
- }
- ESPLOG(LogNormal, "LAgent UpdateLog total=%dms\n", msTick() - startTime);
- return ret;
- }
- CLogGroup* CDBLogAgentBase::checkLogSource(IPropertyTree* logRequest, StringBuffer& source, StringBuffer& logDB)
- {
- if (logSourceCount == 0)
- {//if no log source is configured, use default Log Group and DB
- logDB.set(defaultDB.str());
- source.set(defaultLogGroup.get());
- return logGroups.getValue(defaultLogGroup.get());
- }
- source = logRequest->queryProp(logSourcePath.get());
- if (source.isEmpty())
- throw MakeStringException(EspLoggingErrors::UpdateLogFailed, "Failed to read log Source from request.");
- CLogSource* logSource = logSources.getValue(source.str());
- if (!logSource)
- throw MakeStringException(EspLoggingErrors::UpdateLogFailed, "Log Source %s undefined.", source.str());
- logDB.set(logSource->getDBName());
- return logGroups.getValue(logSource->getGroupName());
- }
- void CDBLogAgentBase::getLoggingTransactionID(StringBuffer& id)
- {
- id.set(loggingTransactionSeed.str()).append("-").append(++loggingTransactionCount);
- }
- bool CDBLogAgentBase::buildUpdateLogStatement(IPropertyTree* logRequest, const char* logDB,
- CLogTable& table, StringBuffer& logID, StringBuffer& updateDBStatement)
- {
- StringBuffer fields, values;
- BoolHash handledFields;
- CIArrayOf<CLogField>& logFields = table.getLogFields();
- ForEachItemIn(i, logFields) //Go through data items to be logged
- {
- CLogField& logField = logFields.item(i);
- StringBuffer colName = logField.getMapTo();
- bool* found = handledFields.getValue(colName.str());
- if (found && *found)
- continue;
- StringBuffer path = logField.getName();
- if (path.charAt(path.length() - 1) == ']')
- {//Attr filter. Separate the last [] from the path.
- const char* pTr = path.str();
- const char* ppTr = strrchr(pTr, '[');
- if (!ppTr)
- continue;
- StringBuffer attr;
- attr.set(ppTr+1);
- attr.setLength(attr.length() - 1);
- path.setLength(ppTr - pTr);
- StringBuffer colValue;
- Owned<IPropertyTreeIterator> itr = logRequest->getElements(path.str());
- ForEach(*itr)
- {//Log the first valid match just in case more than one matches.
- IPropertyTree& ppTree = itr->query();
- colValue.set(ppTree.queryProp(attr.str()));
- if (colValue.length())
- {
- addField(logField, colName.str(), colValue, fields, values);
- handledFields.setValue(colName.str(), true);
- break;
- }
- }
- continue;
- }
- Owned<IPropertyTreeIterator> itr = logRequest->getElements(path.str());
- ForEach(*itr)
- {
- IPropertyTree& ppTree = itr->query();
- StringBuffer colValue;
- if (ppTree.hasChildren()) //This is a tree branch.
- toXML(&ppTree, colValue);
- else
- ppTree.getProp(NULL, colValue);
- if (colValue.length())
- {
- addField(logField, colName.str(), colValue, fields, values);
- handledFields.setValue(colName.str(), true);
- break;
- }
- }
- }
- //add any default fields that may be required but not in request.
- addMissingFields(logFields, handledFields, fields, values);
- appendFieldInfo("log_id", logID, fields, values, true);
- setUpdateLogStatement(logDB, table.getTableName(), fields.str(), values.str(), updateDBStatement);
- return true;
- }
- void CDBLogAgentBase::appendFieldInfo(const char* field, StringBuffer& value, StringBuffer& fields, StringBuffer& values, bool quoted)
- {
- if(values.length() != 0)
- values.append(',');
- if (quoted)
- values.append('\'').append(value.length(), value.str()).append('\'');
- else
- values.append(value.length(), value.str());
- if(fields.length() != 0)
- fields.append(',');
- fields.append(field);
- }
- void CDBLogAgentBase::addMissingFields(CIArrayOf<CLogField>& logFields, BoolHash& handledFields, StringBuffer& fields, StringBuffer& values)
- {
- ForEachItemIn(i, logFields) //Go through data items to be logged
- {
- CLogField& logField = logFields.item(i);
- const char* colName = logField.getMapTo();
- bool* found = handledFields.getValue(colName);
- if (found && *found)
- continue;
- StringBuffer value = logField.getDefault();
- if (!value.isEmpty())
- addField(logField, colName, value, fields, values);
- }
- }
- void CDBLogAgentBase::getTransactionID(StringAttrMapping* transFields, StringBuffer& transactionID)
- {
- //Not implemented
- }
- void CDBLogAgentBase::filterLogContent(IEspUpdateLogRequestWrap* req)
- {
- //No filter in CDBSQLLogAgent
- }
|