ws_workunitsAuditLogs.cpp 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. #include "ws_workunitsService.hpp"
  15. #include "jlib.hpp"
  16. #include "daclient.hpp"
  17. #include "dalienv.hpp"
  18. #include "dadfs.hpp"
  19. #include "daaudit.hpp"
  20. #include "exception_util.hpp"
  21. #include "wujobq.hpp"
  22. #include "eventqueue.hpp"
  23. #include "fileview.hpp"
  24. #include "hqlerror.hpp"
  25. #include "sacmd.hpp"
  26. #include "wuwebview.hpp"
  27. #include "portlist.h"
  28. #include "dllserver.hpp"
  29. #include "schedulectrl.hpp"
  30. #include "scheduleread.hpp"
  31. bool getClusterJobQueueXLS(StringBuffer &xml, const char* cluster, const char* startDate, const char* endDate, const char* showType)
  32. {
  33. CDateTime fromTime;
  34. if(notEmpty(startDate))
  35. fromTime.setString(startDate, NULL, false);
  36. CDateTime toTime;
  37. if(notEmpty(endDate))
  38. toTime.setString(endDate, NULL, false);
  39. xml.append("<XmlSchema name=\"MySchema\">"
  40. "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"qualified\" attributeFormDefault=\"unqualified\">\n"
  41. "<xs:element name=\"Dataset\">"
  42. "<xs:complexType>"
  43. "<xs:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n"
  44. "<xs:element name=\"Row\">"
  45. "<xs:complexType>"
  46. "<xs:sequence>\n");
  47. xml.append("<xs:element name=\"datetime\" type=\"xs:string\"/>\n");
  48. xml.append("<xs:element name=\"running\" type=\"xs:string\"/>\n");
  49. xml.append("<xs:element name=\"queued\" type=\"xs:string\"/>\n");
  50. xml.append("<xs:element name=\"connected\" type=\"xs:string\"/>\n");
  51. xml.append("<xs:element name=\"waiting\" type=\"xs:string20\"/>\n");
  52. xml.append("<xs:element name=\"idlecount\" type=\"xs:string20\"/>\n");
  53. xml.append("<xs:element name=\"running_wuid1\" type=\"xs:string\"/>\n");
  54. xml.append("<xs:element name=\"running_wuid2\" type=\"xs:string\"/>\n");
  55. xml.append( "</xs:sequence>"
  56. "</xs:complexType>"
  57. "</xs:element>\n"
  58. "</xs:sequence>"
  59. "</xs:complexType>"
  60. "</xs:element>\n");
  61. xml.append("<xs:simpleType name=\"string20\"><xs:restriction base=\"xs:string\"><xs:maxLength value=\"20\"/></xs:restriction></xs:simpleType>\n");
  62. xml.append("</xs:schema>");
  63. xml.append("</XmlSchema>").newline();
  64. xml.append("<Dataset");
  65. xml.append(" name=\"data\" xmlSchema=\"MySchema\" ");
  66. xml.append(">").newline();
  67. StringBuffer filter("ThorQueueMonitor");
  68. if (notEmpty(cluster))
  69. filter.appendf(",%s", cluster);
  70. StringAttrArray lines;
  71. queryAuditLogs(fromTime, toTime, filter.str(), lines);
  72. unsigned longest = 0;
  73. unsigned maxConnected = 0;
  74. unsigned maxDisplay = 0;
  75. unsigned showVal = (showType && strieq(showType, "InGraph")) ? 1 : 0;
  76. IArrayOf<IEspThorQueue> items;
  77. WsWuJobQueueAuditInfo jq;
  78. ForEachItemIn(idx, lines)
  79. {
  80. const char* line = lines.item(idx).text;
  81. if(isEmpty(line))
  82. continue;
  83. bool isLast = (idx == (lines.length() - 1));
  84. jq.getAuditLineInfo(lines.item(idx).text, longest, maxConnected, maxDisplay, (isLast && showVal==1) ? 2 : showVal, items);
  85. }
  86. ForEachItemIn(i,items)
  87. {
  88. IEspThorQueue& tq = items.item(i);
  89. xml.append(" <Row>");
  90. appendXMLTag(xml, "datetime", tq.getDT());
  91. appendXMLTag(xml, "running", tq.getRunningWUs());
  92. appendXMLTag(xml, "queued", tq.getQueuedWUs());
  93. appendXMLTag(xml, "connected", tq.getConnectedThors());
  94. appendXMLTag(xml, "waiting", tq.getWaitingThors());
  95. appendXMLTag(xml, "idlecount", tq.getIdledThors());
  96. if (notEmpty(tq.getRunningWU1()))
  97. appendXMLTag(xml, "running_wuid1", tq.getRunningWU1());
  98. if (notEmpty(tq.getRunningWU2()))
  99. appendXMLTag(xml, "running_wuid2", tq.getRunningWU2());
  100. xml.append("</Row>");
  101. xml.newline();
  102. }
  103. xml.append("</Dataset>").newline();
  104. return true;
  105. }
  106. static const long LOGFILESIZELIMIT = 500000; //Limit page size to 500k
  107. inline float timeStrToFloat(const char *timestr, float &val)
  108. {
  109. if (!timestr)
  110. return val;
  111. int hours = 0;
  112. int mins = 0;
  113. while(isdigit(*timestr))
  114. {
  115. hours = 10 * hours + *timestr - '0';
  116. timestr++;
  117. }
  118. if(*timestr == ':')
  119. timestr++;
  120. while(isdigit(*timestr))
  121. {
  122. mins = 10 * mins + (*timestr - '0');
  123. timestr++;
  124. }
  125. val = hours + mins/60.0F;
  126. return val;
  127. }
  128. StringBuffer &getNextStrItem(StringBuffer &s, const char *&finger, const char delim=',')
  129. {
  130. if (!finger)
  131. return s;
  132. const char *endp = strchr(finger, delim);
  133. if (endp)
  134. {
  135. s.append(endp - finger, finger);
  136. finger = endp+1;
  137. }
  138. else
  139. {
  140. s.append(finger);
  141. finger=NULL;
  142. }
  143. return s;
  144. }
  145. IEspECLJob* createEclJobFromAuditLine(double version, const char* str)
  146. {
  147. if(isEmpty(str))
  148. return NULL;
  149. Owned<IEspECLJob> job = createECLJob("", "");
  150. StringBuffer sdate;
  151. getNextStrItem(sdate, str);
  152. if (sdate.length()>=9)
  153. sdate.setCharAt(10, 'T');
  154. if(!str)
  155. return job.getClear();
  156. StringBuffer s;
  157. getNextStrItem(s, str);
  158. if(!str)
  159. return job.getClear();
  160. getNextStrItem(s.clear(), str);
  161. if(!str)
  162. return job.getClear();
  163. job->setCluster(getNextStrItem(s.clear(), str).str());
  164. if(!str)
  165. return job.getClear();
  166. job->setWuid(getNextStrItem(s.clear(), str).str());
  167. if(!str)
  168. return job.getClear();
  169. getNextStrItem(s.clear(), str);
  170. if (version > 1.05)
  171. job->setGraphNum(s.str());
  172. StringBuffer graph("graph");
  173. job->setGraph(graph.append(s).str());
  174. if(!str)
  175. return job.getClear();
  176. getNextStrItem(s.clear(), str);
  177. if (version > 1.05)
  178. job->setSubGraphNum(s.str());
  179. if(!str)
  180. return job.getClear();
  181. getNextStrItem(s.clear(), str);
  182. if (version > 1.05)
  183. job->setNumOfRuns(s.str());
  184. if(!str)
  185. return job.getClear();
  186. getNextStrItem(s.clear(), str);
  187. if (version > 1.05)
  188. job->setDuration(atoi(s.str()) / 1000);
  189. if(!str)
  190. return job.getClear();
  191. if(!strncmp("FAILED", getNextStrItem(s.clear(), str).str(), 6))
  192. job->setState("failed");
  193. else
  194. job->setState("finished");
  195. CDateTime endDT;
  196. endDT.setString(sdate.str(), NULL, true);
  197. CDateTime startDT;
  198. startDT.set(endDT.getSimple() - job->getDuration());
  199. job->setStartedDate(startDT.getString(s.clear(), false).append('Z').str());
  200. job->setFinishedDate(endDT.getString(s.clear(), false).append('Z').str());
  201. return job.getClear();
  202. }
  203. bool getClusterJobXLS(double version, StringBuffer &xml, const char* cluster, const char* startDate, const char* endDate, bool showall, const char* busStartStr, const char* busEndStr)
  204. {
  205. float busStart = 0;
  206. float busEnd = 24;
  207. if(showall)
  208. {
  209. timeStrToFloat(busStartStr, busStart);
  210. timeStrToFloat(busEndStr, busEnd);
  211. if(busStart <= 0 || busStart > 24 || busStart >= busEnd)
  212. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid business hours");
  213. }
  214. CDateTime fromTime;
  215. if(notEmpty(startDate))
  216. fromTime.setString(startDate, NULL, false);
  217. CDateTime toTime;
  218. if(notEmpty(endDate))
  219. toTime.setString(endDate, NULL, false);
  220. xml.append("<XmlSchema name=\"MySchema\">");
  221. xml.append("<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"qualified\" attributeFormDefault=\"unqualified\">\n"
  222. "<xs:element name=\"Dataset\">"
  223. "<xs:complexType>"
  224. "<xs:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n"
  225. "<xs:element name=\"Row\">"
  226. "<xs:complexType>"
  227. "<xs:sequence>\n");
  228. xml.append("<xs:element name=\"wuid\" type=\"xs:string\"/>\n");
  229. xml.append("<xs:element name=\"graph\" type=\"xs:string\"/>\n");
  230. xml.append("<xs:element name=\"sub-graph\" type=\"xs:string\"/>\n");
  231. xml.append("<xs:element name=\"runs\" type=\"xs:string\"/>\n");
  232. xml.append("<xs:element name=\"started\" type=\"xs:string20\"/>\n");
  233. xml.append("<xs:element name=\"finished\" type=\"xs:string20\"/>\n");
  234. xml.append("<xs:element name=\"duration\" type=\"xs:string\"/>\n");
  235. xml.append("<xs:element name=\"cluster\" type=\"xs:string\"/>\n");
  236. xml.append("<xs:element name=\"state\" type=\"xs:string\"/>\n");
  237. xml.append( "</xs:sequence>"
  238. "</xs:complexType>"
  239. "</xs:element>\n"
  240. "</xs:sequence>"
  241. "</xs:complexType>"
  242. "</xs:element>\n");
  243. xml.append("<xs:simpleType name=\"string20\"><xs:restriction base=\"xs:string\"><xs:maxLength value=\"20\"/></xs:restriction></xs:simpleType>\n");
  244. xml.append("</xs:schema>");
  245. xml.append("</XmlSchema>").newline();
  246. xml.append("<Dataset name=\"data\" xmlSchema=\"MySchema\">").newline();
  247. StringBuffer filter("Timing,ThorGraph");
  248. if(notEmpty(cluster))
  249. filter.append(',').append(cluster);
  250. StringAttrArray jobs;
  251. queryAuditLogs(fromTime, toTime, filter.str(), jobs);
  252. IArrayOf<IEspECLJob> jobList;
  253. ForEachItemIn(idx, jobs)
  254. {
  255. if(jobs.item(idx).text.isEmpty())
  256. continue;
  257. Owned<IEspECLJob> job = createEclJobFromAuditLine(version, jobs.item(idx).text.get());
  258. CDateTime tTime;
  259. unsigned year, month, day, hour, minute, second, nano;
  260. tTime.setString(job->getStartedDate(), NULL, true);
  261. tTime.getDate(year, month, day, true);
  262. tTime.getTime(hour, minute, second, nano, true);
  263. StringBuffer started;
  264. started.appendf("%4d-%02d-%02d %02d:%02d:%02d",year,month,day,hour,minute,second);
  265. tTime.setString(job->getFinishedDate(), NULL, true);
  266. tTime.getDate(year, month, day, true);
  267. tTime.getTime(hour, minute, second, nano, true);
  268. StringBuffer finished;
  269. finished.appendf("%4d-%02d-%02d %02d:%02d:%02d",year,month,day,hour,minute,second);
  270. xml.append(" <Row>");
  271. appendXMLTag(xml, "wuid", job->getWuid());
  272. appendXMLTag(xml, "graph", job->getGraphNum());
  273. appendXMLTag(xml, "sub-graph", job->getSubGraphNum());
  274. appendXMLTag(xml, "runs", job->getNumOfRuns());
  275. appendXMLTag(xml, "started", started.str());
  276. appendXMLTag(xml, "finished", finished.str());
  277. xml.appendf("<duration>%d</duration>", job->getDuration());
  278. appendXMLTag(xml, "cluster", job->getCluster());
  279. appendXMLTag(xml, "state", job->getState());
  280. xml.append("</Row>").newline();
  281. jobList.append(*job.getClear());
  282. }
  283. xml.append("</Dataset>").newline();
  284. return true;
  285. }
  286. class CJobUsage : public CInterface
  287. {
  288. public:
  289. StringBuffer m_date;
  290. float m_usage, m_busage, m_nbusage;
  291. public:
  292. IMPLEMENT_IINTERFACE;
  293. CJobUsage()
  294. {
  295. m_usage = 0.0;
  296. m_busage = 0.0;
  297. m_nbusage = 0.0;
  298. };
  299. };
  300. typedef CIArrayOf<CJobUsage> JobUsageArray;
  301. //what???
  302. int ZCMJD(unsigned y, unsigned m, unsigned d)
  303. {
  304. if (m<3)
  305. {
  306. m += 12 ;
  307. y--;
  308. }
  309. return -678973 + d + (((153*m-2)/5)|0) + 365*y + ((y/4)|0) - ((y/100)|0) + ((y/400)|0);
  310. }
  311. void AddToClusterJobXLS(JobUsageArray& jobsummary, CDateTime &adjStart, CDateTime &adjEnd, int first, float busStart, float busEnd)
  312. {
  313. unsigned year0, month0, day0, hour0, minute0, second0, nano0;
  314. adjStart.getDate(year0, month0, day0, true);
  315. adjStart.getTime(hour0, minute0, second0, nano0, true);
  316. unsigned year1, month1, day1, hour1, minute1, second1, nano1;
  317. adjEnd.getDate(year1, month1, day1, true);
  318. adjEnd.getTime(hour1, minute1, second1, nano1, true);
  319. busStart *= 3600.0;
  320. busEnd *= 3600.0;
  321. float x1 = 3600.0F*hour0 + 60.0F*minute0 + second0;
  322. int y1 = ZCMJD(year0, month0, day0)-first;
  323. float x2 = 3600.0F*hour1 + 60.0F*minute1 + second1;
  324. int y2 = ZCMJD(year1, month1, day1)-first;
  325. for(int y=y1; y<=y2; y++)
  326. {
  327. if ((y < 0) || (y > (int)jobsummary.length() - 1))
  328. continue;
  329. CJobUsage& jobUsage = jobsummary.item(y);
  330. float xx1= (y==y1 ? x1 : 0.0F);
  331. float xx2= (y==y2 ? x2 : 86400.0F);
  332. jobUsage.m_usage += (xx2-xx1)/864.0F;
  333. float bhours = ((busEnd < xx2)? busEnd : xx2) - ((busStart > xx1) ? busStart : xx1);
  334. if(bhours < 0.0)
  335. bhours = 0.0;
  336. float nbhours = (xx2 - xx1 - bhours);
  337. if(busStart + (86400.0 - busEnd) > 0.001)
  338. jobUsage.m_nbusage += 100 * nbhours/(busStart + (86400.0F - busEnd));
  339. if(busEnd - busStart > 0.001)
  340. jobUsage.m_busage += 100*bhours/(busEnd - busStart);
  341. }
  342. return;
  343. }
  344. bool readECLWUCurrentJob(const char* curjob, const char* clusterName, const char* toDate, StringBuffer& dtStr, StringBuffer& actionStr, StringBuffer& wuidStr, StringBuffer& graphStr, StringBuffer& subGraphStr, StringBuffer& clusterStr)
  345. {
  346. if(!curjob || !*curjob)
  347. return false;
  348. // startdate
  349. const char* bptr = curjob;
  350. const char* eptr = strchr(bptr, ',');
  351. if(!eptr)
  352. return false;
  353. StringBuffer dt;
  354. dt.clear().append(eptr - bptr, bptr);
  355. dt.setCharAt(10, 'T');
  356. if (strcmp(dt.str(), toDate) > 0)
  357. return false;
  358. CDateTime enddt;
  359. enddt.setString(dt.str(), NULL, true);
  360. dt.clear();
  361. enddt.getString(dt, false);
  362. dt.append('Z');
  363. //Progress
  364. bptr = eptr + 1;
  365. eptr = strchr(bptr, ',');
  366. if(!eptr)
  367. return false;
  368. //Thor
  369. bptr = eptr + 1;
  370. eptr = strchr(bptr, ',');
  371. if(!eptr)
  372. return false;
  373. // action name
  374. char action[256];
  375. bptr = eptr + 1;
  376. eptr = strchr(bptr, ',');
  377. if(!eptr)
  378. return false;
  379. int len = eptr - bptr;
  380. strncpy(action, bptr, len);
  381. action[len] = 0;
  382. // cluster name
  383. char cluster[256];
  384. bptr = eptr + 1;
  385. eptr = strchr(bptr, ',');
  386. if(!eptr)
  387. return false;
  388. len = eptr - bptr;
  389. strncpy(cluster, bptr, len);
  390. cluster[len] = 0;
  391. if (cluster && *cluster)
  392. {
  393. clusterStr.clear().append(cluster);
  394. if (clusterName && *clusterName && stricmp(cluster, clusterName))
  395. return false;
  396. }
  397. dtStr = dt;
  398. actionStr.clear().append(action);
  399. if (!stricmp(action, "startup") || !stricmp(action, "terminate"))
  400. return true;
  401. //WUID
  402. bptr = eptr + 1;
  403. eptr = strchr(bptr, ',');
  404. if(!eptr)
  405. return false;
  406. wuidStr.clear().append(eptr - bptr, bptr);
  407. //graph number
  408. char graph[32];
  409. bptr = eptr + 1;
  410. eptr = strchr(bptr, ',');
  411. if(!eptr)
  412. return false;
  413. len = eptr - bptr;
  414. if (bptr[0] == 'g' && len > 5)
  415. {
  416. bptr += 5;
  417. len = eptr - bptr;
  418. }
  419. strncpy(graph, bptr, len);
  420. graph[len] = 0;
  421. graphStr.clear().append(eptr - bptr, bptr);
  422. if (!stricmp(action, "start") || !stricmp(action, "stop"))
  423. return true;
  424. //subgraph number
  425. char subgraph[32];
  426. bptr = eptr + 1;
  427. eptr = strchr(bptr, ',');
  428. if(!eptr)
  429. {
  430. strcpy(subgraph, bptr);
  431. }
  432. else
  433. {
  434. len = eptr - bptr;
  435. strncpy(subgraph, bptr, len);
  436. subgraph[len] = 0;
  437. }
  438. subGraphStr.clear().append(subgraph);
  439. return true;
  440. }
  441. void addUnfinishedECLWUs(IArrayOf<IEspECLJob>& eclJobList, const char* wuid, const char* graph, const char* subGraph,
  442. const char* cluster, const char* dt, const char* dt1, StringArray& unfinishedWUIDs, StringArray& unfinishedGraphs,
  443. StringArray& unfinishedSubGraphs, StringArray& unfinishedClusters, StringArray& unfinishedWUStarttime, StringArray& unfinishedWUEndtime)
  444. {
  445. bool bFound = false;
  446. ForEachItemIn(idx, eclJobList)
  447. {
  448. IConstECLJob& curECLJob = eclJobList.item(idx);
  449. const char *eclwuid = curECLJob.getWuid();
  450. const char *eclgraph = curECLJob.getGraphNum();
  451. const char *eclsubgraph = curECLJob.getSubGraphNum();
  452. const char *ecldate = curECLJob.getFinishedDate();
  453. if (!eclwuid || !*eclwuid || stricmp(eclwuid, wuid))
  454. continue;
  455. if (!eclgraph || !*eclgraph || stricmp(eclgraph, graph))
  456. continue;
  457. if (!eclsubgraph || !*eclsubgraph || stricmp(eclsubgraph, subGraph))
  458. continue;
  459. //if (!ecldate || !*ecldate || (stricmp(ecldate, dt) < 0) || (stricmp(ecldate, dt1) > 0))
  460. // continue;
  461. if (!ecldate || !*ecldate)
  462. continue;
  463. int test = stricmp(ecldate, dt);
  464. if (test < 0)
  465. continue;
  466. test = stricmp(ecldate, dt1);
  467. if (test > 0)
  468. continue;
  469. bFound = true;
  470. break;
  471. }
  472. if (!bFound)
  473. {
  474. unfinishedWUIDs.append(wuid);
  475. StringBuffer graph0("graph");
  476. graph0.append(graph);
  477. unfinishedGraphs.append(graph0);
  478. unfinishedSubGraphs.append(subGraph);
  479. unfinishedClusters.append(cluster);
  480. unfinishedWUStarttime.append(dt);
  481. unfinishedWUEndtime.append(dt1);
  482. }
  483. return;
  484. }
  485. const unsigned MAXSUBGRAPHDAYS = 10;
  486. bool getPreviousUnfinishedECLWU(CDateTime fromTime, CDateTime toTime, const char* toDate, const char* cluster,
  487. StringBuffer& wuidStr, StringBuffer& graphStr, StringBuffer& subGraphStr, StringBuffer& clusterStr, StringBuffer& dtStr)
  488. {
  489. bool bFound = false;
  490. wuidStr.clear();
  491. graphStr.clear();
  492. subGraphStr.clear();
  493. dtStr.clear();
  494. StringBuffer filter0("Progress,Thor");
  495. CDateTime fromTime1 = fromTime, toTime1;
  496. bool bStop = false;
  497. for (unsigned day = 0; !bStop && day < MAXSUBGRAPHDAYS; day++)
  498. {
  499. toTime1 = fromTime1;
  500. fromTime1.adjustTime(-1440);
  501. StringAttrArray jobs1;
  502. queryAuditLogs(fromTime1, toTime1, filter0.str(), jobs1);
  503. #if 0
  504. char* str1 = "2010-10-04 07:39:04 ,Progress,Thor,StartSubgraph,thor,W20100929-073902,5,1,thor,thor.thor";
  505. char* str2 = "2010-10-04 15:53:43 ,Progress,Thor,Startup,thor,thor,thor.thor,//10.173.51.20/c$/thor_logs/09_29_2010_15_52_39/THORMASTER.log";
  506. char* str3 = "2010-10-04 17:52:31 ,Progress,Thor,Start,thor,W20100929-075230,graph1,r3gression,thor,thor.thor";
  507. jobs1.append(*new StringAttrItem(str2, strlen(str2)));
  508. jobs1.append(*new StringAttrItem(str1, strlen(str1)));
  509. jobs1.append(*new StringAttrItem(str3, strlen(str3)));
  510. #endif
  511. ForEachItemInRev(idx1, jobs1)
  512. {
  513. const char* curjob = jobs1.item(idx1).text;
  514. if(!curjob || !*curjob)
  515. continue;
  516. StringBuffer actionStr, clusterStr;
  517. if (!readECLWUCurrentJob(curjob, cluster, toDate, dtStr, actionStr, wuidStr, graphStr, subGraphStr, clusterStr))
  518. continue;
  519. if (!stricmp(actionStr.str(), "StartSubgraph") && (wuidStr.length() > 0) && (graphStr.length() > 0))
  520. {
  521. bFound = true;
  522. bStop = true;
  523. break;
  524. }
  525. if (!stricmp(actionStr.str(), "Startup") || !stricmp(actionStr.str(), "Terminate"))
  526. {
  527. bStop = true;
  528. break;
  529. }
  530. }
  531. }
  532. return bFound;
  533. }
  534. //Tony ToBeRefactored
  535. void findUnfinishedECLWUs(IArrayOf<IEspECLJob>& eclJobList, CDateTime fromTime, CDateTime toTime, const char* toDate, const char* cluster, StringArray& unfinishedWUIDs,
  536. StringArray& unfinishedGraphs, StringArray& unfinishedSubGraphs, StringArray& unfinishedClusters, StringArray& unfinishedWUStarttime, StringArray& unfinishedWUEndtime)
  537. {
  538. StringAttrArray jobs1;
  539. StringBuffer filter1("Progress,Thor");
  540. queryAuditLogs(fromTime, toTime, filter1.str(), jobs1);
  541. bool bAbnormalWU = false;
  542. int len = jobs1.length();
  543. StringBuffer dtStr, actionStr, wuidStr, graphStr, subGraphStr, clusterStr;
  544. ForEachItemIn(idx1, jobs1)
  545. {
  546. const char* curjob = jobs1.item(idx1).text;
  547. if(!curjob || !*curjob)
  548. continue;
  549. wuidStr.clear();
  550. graphStr.clear();
  551. subGraphStr.clear();
  552. if (!readECLWUCurrentJob(curjob, cluster, toDate, dtStr, actionStr, wuidStr, graphStr, subGraphStr, clusterStr))
  553. continue;
  554. if (stricmp(actionStr.str(), "Start"))
  555. continue;
  556. bAbnormalWU = true;
  557. int nextIndex = idx1 + 1;
  558. int idx2 = nextIndex;
  559. while (idx2 < len)
  560. {
  561. const char* curjob1 = jobs1.item(idx2).text;
  562. if(!curjob1 || !*curjob1)
  563. continue;
  564. StringBuffer dtStr1, actionStr1, wuidStr1, graphStr1, subGraphStr1, clusterStr1;
  565. if (readECLWUCurrentJob(curjob1, cluster, toDate, dtStr1, actionStr1, wuidStr1, graphStr1, subGraphStr1, clusterStr1))
  566. {
  567. if (!stricmp(wuidStr.str(), wuidStr1.str()) && !stricmp(graphStr.str(), graphStr1.str()))
  568. {
  569. if (!stricmp(actionStr1.str(), "Stop") )
  570. {
  571. bAbnormalWU = false;
  572. break;
  573. }
  574. else if (!stricmp(actionStr1.str(), "Start"))
  575. {
  576. break;
  577. }
  578. }
  579. }
  580. idx2++;
  581. }
  582. //If the WU did not finish by itself, let's check whether the cluster was stopped before the WU finished.
  583. if (bAbnormalWU)
  584. {
  585. int idx2 = nextIndex;
  586. while (idx2 < len)
  587. {
  588. const char* curjob1 = jobs1.item(idx2).text;
  589. if(!curjob1 || !*curjob1)
  590. continue;
  591. StringBuffer dtStr1, actionStr1, wuidStr1, graphStr1, subGraphStr1, clusterStr1;
  592. if (!readECLWUCurrentJob(curjob1, cluster, toDate, dtStr1, actionStr1, wuidStr1, graphStr1, subGraphStr1, clusterStr1))
  593. {
  594. idx2++;
  595. continue;
  596. }
  597. if (!stricmp(actionStr1.str(), "StartSubgraph") && !stricmp(wuidStr.str(), wuidStr1.str()) && !stricmp(graphStr.str(), graphStr1.str()))
  598. {
  599. //update subgraph number
  600. subGraphStr.clear().append(subGraphStr1.str());
  601. dtStr.clear().append(dtStr1.str());
  602. clusterStr.clear().append(clusterStr1.str());
  603. idx2++;
  604. continue;
  605. }
  606. if (stricmp(actionStr1.str(), "Startup") && stricmp(actionStr1.str(), "Terminate"))
  607. {
  608. idx2++;
  609. continue;
  610. }
  611. addUnfinishedECLWUs(eclJobList, wuidStr.str(), graphStr.str(), subGraphStr.str(), clusterStr.str(), dtStr.str(), dtStr1.str(),
  612. unfinishedWUIDs, unfinishedGraphs, unfinishedSubGraphs, unfinishedClusters, unfinishedWUStarttime, unfinishedWUEndtime);
  613. bAbnormalWU = false;
  614. break;
  615. }
  616. if (bAbnormalWU)
  617. {
  618. addUnfinishedECLWUs(eclJobList, wuidStr.str(), graphStr.str(), subGraphStr.str(), clusterStr.str(), dtStr.str(), toDate,
  619. unfinishedWUIDs, unfinishedGraphs, unfinishedSubGraphs, unfinishedClusters, unfinishedWUStarttime, unfinishedWUEndtime);
  620. bAbnormalWU = false;
  621. }
  622. }
  623. }
  624. //What if a WU started before *and* ended after the search time range
  625. if ((eclJobList.length() < 1) && (unfinishedWUIDs.length() < 1))
  626. {
  627. if (getPreviousUnfinishedECLWU(fromTime, toTime, toDate, cluster, wuidStr, graphStr, subGraphStr, clusterStr, dtStr))
  628. {
  629. addUnfinishedECLWUs(eclJobList, wuidStr.str(), graphStr.str(), subGraphStr.str(), clusterStr.str(), dtStr.str(), toDate,
  630. unfinishedWUIDs, unfinishedGraphs, unfinishedSubGraphs, unfinishedClusters, unfinishedWUStarttime, unfinishedWUEndtime);
  631. }
  632. }
  633. return;
  634. }
  635. bool getClusterJobSummaryXLS(double version, StringBuffer &xml, const char* cluster, const char* startDate, const char* endDate, bool showall, const char* busStartStr, const char* busEndStr)
  636. {
  637. float busStart = 0;
  638. float busEnd = 24;
  639. if(showall)
  640. {
  641. timeStrToFloat(busStartStr, busStart);
  642. timeStrToFloat(busEndStr, busEnd);
  643. if(busStart <= 0 || busStart > 24 || busStart >= busEnd)
  644. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid business hours");
  645. }
  646. CDateTime fromTime;
  647. if(notEmpty(startDate))
  648. fromTime.setString(startDate, NULL, false);
  649. CDateTime toTime;
  650. int delayTime = -240; //4 hour time difference
  651. bool extendedToNextDay = false;
  652. if(notEmpty(endDate))
  653. {
  654. toTime.setString(endDate, NULL, false);
  655. unsigned year, month, day, day1;
  656. CDateTime tTime = toTime;
  657. tTime.getDate(year, month, day);
  658. tTime.adjustTime(delayTime);
  659. tTime.getDate(year, month, day1);
  660. if (day1 < day)
  661. extendedToNextDay = true;
  662. }
  663. StringAttrArray jobs;
  664. StringBuffer filter("Timing,ThorGraph");
  665. if(notEmpty(cluster))
  666. filter.append(',').append(cluster);
  667. queryAuditLogs(fromTime, toTime, filter.str(), jobs);
  668. unsigned year, month, day;
  669. fromTime.getDate(year, month, day);
  670. int first = ZCMJD(year, month, day);
  671. toTime.getDate(year, month, day);
  672. int last = ZCMJD(year, month, day);
  673. if (last < first)
  674. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid day range");
  675. CDateTime usageDT(fromTime);
  676. JobUsageArray jobUsages;
  677. for (int i = first; i <= last; i++)
  678. {
  679. Owned<CJobUsage> jobUsage = new CJobUsage();
  680. usageDT.getDateString(jobUsage->m_date);
  681. jobUsages.append(*jobUsage.getClear());
  682. usageDT.adjustTime(60*24);
  683. }
  684. IArrayOf<IEspECLJob> jobList;
  685. ForEachItemIn(idx, jobs)
  686. {
  687. if(jobs.item(idx).text.isEmpty())
  688. continue;
  689. Owned<IEspECLJob> job = createEclJobFromAuditLine(version, jobs.item(idx).text.get());
  690. CDateTime adjStart;
  691. adjStart.setString(job->getStartedDate(),NULL,true);
  692. adjStart.adjustTime(delayTime);
  693. CDateTime adjEnd;
  694. adjEnd.setString(job->getFinishedDate(),NULL,true);
  695. adjEnd.adjustTime(delayTime);
  696. AddToClusterJobXLS(jobUsages, adjStart, adjEnd, first, busStart, busEnd);
  697. jobList.append(*job.getClear());
  698. }
  699. StringBuffer s;
  700. StringArray unfinishedWUIDs, unfinishedGraphs, unfinishedSubGraphs, unfinishedClusters, unfinishedWUStarttime, unfinishedWUEndtime;
  701. findUnfinishedECLWUs(jobList, fromTime, toTime, toTime.getString(s).str(), cluster, unfinishedWUIDs, unfinishedGraphs, unfinishedSubGraphs, unfinishedClusters, unfinishedWUStarttime, unfinishedWUEndtime);
  702. ForEachItemIn(idx3, unfinishedWUIDs)
  703. {
  704. CDateTime adjStart;
  705. adjStart.setString(unfinishedWUStarttime.item(idx3), NULL, true);
  706. adjStart.adjustTime(delayTime);
  707. CDateTime adjEnd;
  708. adjEnd.setString(unfinishedWUEndtime.item(idx3),NULL,true);
  709. adjEnd.adjustTime(delayTime);
  710. AddToClusterJobXLS(jobUsages, adjStart, adjEnd, first, busStart, busEnd);
  711. }
  712. xml.append("<XmlSchema name=\"MySchema\">");
  713. xml.append(
  714. "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"qualified\" attributeFormDefault=\"unqualified\">\n"
  715. "<xs:element name=\"Dataset\">"
  716. "<xs:complexType>"
  717. "<xs:sequence minOccurs=\"0\" maxOccurs=\"unbounded\">\n"
  718. "<xs:element name=\"Row\">"
  719. "<xs:complexType>"
  720. "<xs:sequence>\n");
  721. xml.append("<xs:element name=\"Date\" type=\"xs:string\"/>\n");
  722. xml.append("<xs:element name=\"Business\" type=\"xs:string\"/>\n");
  723. xml.append("<xs:element name=\"Non-business\" type=\"xs:string\"/>\n");
  724. xml.append("<xs:element name=\"Overall\" type=\"xs:string\"/>\n");
  725. xml.append( "</xs:sequence>"
  726. "</xs:complexType>"
  727. "</xs:element>\n"
  728. "</xs:sequence>"
  729. "</xs:complexType>"
  730. "</xs:element>\n");
  731. xml.append("<xs:simpleType name=\"string20\"><xs:restriction base=\"xs:string\"><xs:maxLength value=\"20\"/></xs:restriction></xs:simpleType>\n");
  732. xml.append("</xs:schema>");
  733. xml.append("</XmlSchema>").newline();
  734. xml.append("<Dataset name=\"data\" xmlSchema=\"MySchema\" >").newline();
  735. StringBuffer percentageStr;
  736. percentageStr.append("%");
  737. int lastUsage = jobUsages.length();
  738. if (extendedToNextDay)
  739. lastUsage --;
  740. for (int i0 = 0; i0 < lastUsage; i0++)
  741. {
  742. CJobUsage& jobUsage = jobUsages.item(i0);
  743. xml.append(" <Row>");
  744. xml.appendf("<Date>%s</Date>", jobUsage.m_date.str());
  745. xml.appendf("<Business>%3.0f %s</Business>", jobUsage.m_busage, percentageStr.str());
  746. xml.appendf("<Non-business>%3.0f %s</Non-business>", jobUsage.m_nbusage, percentageStr.str());
  747. xml.appendf("<Overall>%3.0f %s</Overall>", jobUsage.m_usage, percentageStr.str());
  748. xml.append(" </Row>");
  749. }
  750. xml.append("</Dataset>").newline();
  751. return true;
  752. }
  753. inline StringBuffer &appendQuoted(StringBuffer &s, const char *val, bool first=false, const char q='\'')
  754. {
  755. if (!first)
  756. s.append(',');
  757. return s.append(q).append(val).append(q);
  758. }
  759. inline StringBuffer &appendQuoted(StringBuffer &s, float val, bool first=false, const char q='\'')
  760. {
  761. if (!first)
  762. s.append(',');
  763. return s.append(q).append(val).append(q);
  764. }
  765. inline StringBuffer &appendQuoted(StringBuffer &s, unsigned val, bool first=false, const char q='\'')
  766. {
  767. if (!first)
  768. s.append(',');
  769. return s.append(q).append(val).append(q);
  770. }
  771. void streamJobListResponse(IEspContext &context, const char *cluster, const char *from , const char *to, CHttpResponse* response, bool showall, float bbtime, float betime, const char *xls)
  772. {
  773. CDateTime fromTime;
  774. StringBuffer fromstr;
  775. if (notEmpty(from))
  776. {
  777. fromTime.setString(from, NULL, false);
  778. fromTime.getString(fromstr, false);
  779. }
  780. CDateTime toTime;
  781. StringBuffer tostr;
  782. if(notEmpty(to))
  783. {
  784. toTime.setString(to,NULL,false);
  785. toTime.getString(tostr, false);
  786. }
  787. StringBuffer sb;
  788. sb.append("<script language=\"javascript\">parent.displayLegend(");
  789. appendQuoted(sb, fromstr.str(), true);
  790. appendQuoted(sb, tostr.str());
  791. appendQuoted(sb, showall ? "1" : "0");
  792. sb.append(")</script>\r\n");
  793. response->sendChunk(sb.str());
  794. sb.clear();
  795. sb.append("<script language=\"javascript\">parent.displayBegin(");
  796. appendQuoted(sb, fromstr.str(), true);
  797. appendQuoted(sb, tostr.str());
  798. appendQuoted(sb, showall ? "1" : "0");
  799. sb.append(")</script>\r\n");
  800. response->sendChunk(sb.str());
  801. sb.clear();
  802. StringBuffer filter("Timing,ThorGraph");
  803. if(notEmpty(cluster))
  804. filter.appendf(",%s", cluster);
  805. StringAttrArray jobs;
  806. queryAuditLogs(fromTime, toTime, filter.str(), jobs);
  807. sb.append("<script language=\"javascript\">\r\n");
  808. unsigned count=0;
  809. IArrayOf<IEspECLJob> eclJobList;
  810. ForEachItemIn(idx, jobs)
  811. {
  812. if(!jobs.item(idx).text.length())
  813. continue;
  814. Owned<IEspECLJob> job = createEclJobFromAuditLine(context.getClientVersion(), jobs.item(idx).text.get());
  815. sb.append("parent.displayJob(");
  816. appendQuoted(sb, job->getWuid(), true);
  817. appendQuoted(sb, job->getGraph());
  818. appendQuoted(sb, job->getStartedDate());
  819. appendQuoted(sb, job->getFinishedDate());
  820. appendQuoted(sb, job->getCluster());
  821. appendQuoted(sb, job->getState());
  822. if (showall)
  823. sb.append(",\'\',\'1\'");
  824. else
  825. sb.append(",\'\',\'0\'");
  826. sb.append(',').append(bbtime).append(',').append(betime).append(")\r\n");
  827. if(++count>=50)
  828. {
  829. sb.append("</script>\r\n");
  830. response->sendChunk(sb.str());
  831. sb.clear().append("<script language=\"javascript\">\r\n");
  832. count=0;
  833. }
  834. eclJobList.append(*job.getClear());
  835. }
  836. //Find out which WUs stopped by abnormal thor termination
  837. StringArray unfinishedWUIDs, unfinishedGraphs, unfinishedSubGraphs, unfinishedClusters, unfinishedWUStarttime, unfinishedWUEndtime;
  838. findUnfinishedECLWUs(eclJobList, fromTime, toTime, tostr.str(), cluster, unfinishedWUIDs, unfinishedGraphs, unfinishedSubGraphs, unfinishedClusters, unfinishedWUStarttime, unfinishedWUEndtime);
  839. if (unfinishedWUIDs.ordinality())
  840. {
  841. ForEachItemIn(idx3, unfinishedWUIDs)
  842. {
  843. CDateTime tTime;
  844. unsigned year, month, day, hour, minute, second, nano;
  845. tTime.setString(unfinishedWUStarttime.item(idx3),NULL,true);
  846. tTime.getDate(year, month, day, true);
  847. tTime.getTime(hour, minute, second, nano, true);
  848. StringBuffer started, finished;
  849. started.appendf("%4d-%02d-%02dT%02d:%02d:%02dZ",year,month,day,hour,minute,second);
  850. if (notEmpty(unfinishedWUEndtime.item(idx3)))
  851. {
  852. tTime.setString(unfinishedWUEndtime.item(idx3),NULL,true);
  853. tTime.getDate(year, month, day, true);
  854. tTime.getTime(hour, minute, second, nano, true);
  855. finished.appendf("%4d-%02d-%02dT%02d:%02d:%02dZ",year,month,day,hour,minute,second);
  856. }
  857. sb.append("parent.displayJob(");
  858. appendQuoted(sb, unfinishedWUIDs.item(idx3), true);
  859. appendQuoted(sb, unfinishedGraphs.item(idx3));
  860. appendQuoted(sb, started.str());
  861. appendQuoted(sb, finished.str());
  862. appendQuoted(sb, unfinishedClusters.item(idx3));
  863. appendQuoted(sb, "not finished");
  864. if (showall)
  865. sb.append(",\'\',\'1\'");
  866. else
  867. sb.append(",\'\',\'0\'");
  868. sb.append(',').append(bbtime).append(',').append(betime).append(")\r\n");
  869. if(++count>=50)
  870. {
  871. sb.append("</script>\r\n");
  872. response->sendChunk(sb.str());
  873. sb.clear().append("<script language=\"javascript\">\r\n");
  874. count=0;
  875. }
  876. }
  877. }
  878. sb.append("</script>\r\n");
  879. response->sendChunk(sb.str());
  880. sb.clear().append("<script language=\"javascript\">\r\n");
  881. sb.append("parent.displaySasha();\r\nparent.displayEnd(");
  882. appendQuoted(sb, xls, true).append(")</script>\r\n");
  883. response->sendChunk(sb.str());
  884. }
  885. bool checkSameStrings(const char* s1, const char* s2)
  886. {
  887. if (s1)
  888. {
  889. if (s2 && streq(s1, s2))
  890. return true;
  891. }
  892. else if (!s2)
  893. return true;
  894. return false;
  895. }
  896. bool checkNewThorQueueItem(IEspThorQueue* tq, unsigned showAll, IArrayOf<IEspThorQueue>& items)
  897. {
  898. bool bAdd = false;
  899. if (showAll < 1) //show every lines
  900. bAdd = true;
  901. else if (items.length() < 1)
  902. bAdd = true;
  903. else if (showAll > 1) //last line now
  904. {
  905. IEspThorQueue& tq0 = items.item(items.length()-1);
  906. if (!checkSameStrings(tq->getDT(), tq0.getDT()))
  907. bAdd = true;
  908. }
  909. else
  910. {
  911. IEspThorQueue& tq0 = items.item(items.length()-1);
  912. if (!checkSameStrings(tq->getRunningWUs(), tq0.getRunningWUs()))
  913. bAdd = true;
  914. if (!checkSameStrings(tq->getQueuedWUs(), tq0.getQueuedWUs()))
  915. bAdd = true;
  916. if (!checkSameStrings(tq->getConnectedThors(), tq0.getConnectedThors()))
  917. bAdd = true;
  918. if (!checkSameStrings(tq->getConnectedThors(), tq0.getConnectedThors()))
  919. bAdd = true;
  920. if (!checkSameStrings(tq->getRunningWU1(), tq0.getRunningWU1()))
  921. bAdd = true;
  922. if (!checkSameStrings(tq->getRunningWU2(), tq0.getRunningWU2()))
  923. bAdd = true;
  924. }
  925. return bAdd;
  926. }
  927. void appendQueueInfoFromAuditLine(IArrayOf<IEspThorQueue>& items, const char* line, unsigned& longestQueue, unsigned& maxConnected, unsigned maxDisplay, unsigned showAll)
  928. {
  929. //2009-08-12 02:44:12 ,ThorQueueMonitor,thor400_88_dev,0,0,1,1,114,---,---
  930. if(!line || !*line)
  931. return;
  932. Owned<IEspThorQueue> tq = createThorQueue();
  933. StringBuffer dt, runningWUs, queuedWUs, waitingThors, connectedThors, idledThors, runningWU1, runningWU2;
  934. // date/time
  935. const char* bptr = line;
  936. const char* eptr = strchr(bptr, ',');
  937. if(eptr)
  938. dt.append(eptr - bptr, bptr);
  939. else
  940. dt.append(bptr);
  941. tq->setDT(dt.str());
  942. if(!eptr)
  943. {
  944. if (checkNewThorQueueItem(tq, showAll, items))
  945. items.append(*tq.getClear());
  946. return;
  947. }
  948. //skip title
  949. bptr = eptr + 1;
  950. eptr = strchr(bptr, ',');
  951. if(!eptr)
  952. {
  953. if (checkNewThorQueueItem(tq, showAll, items))
  954. items.append(*tq.getClear());
  955. return;
  956. }
  957. //skip queue name
  958. bptr = eptr + 1;
  959. eptr = strchr(bptr, ',');
  960. if(!eptr)
  961. {
  962. if (checkNewThorQueueItem(tq, showAll, items))
  963. items.append(*tq.getClear());
  964. return;
  965. }
  966. //running
  967. bptr = eptr + 1;
  968. eptr = strchr(bptr, ',');
  969. if(eptr)
  970. runningWUs.append(eptr - bptr, bptr);
  971. else
  972. runningWUs.append(bptr);
  973. tq->setRunningWUs(runningWUs.str());
  974. if(!eptr)
  975. {
  976. if (checkNewThorQueueItem(tq, showAll, items))
  977. items.append(*tq.getClear());
  978. return;
  979. }
  980. //queued
  981. bptr = eptr + 1;
  982. eptr = strchr(bptr, ',');
  983. if(eptr)
  984. queuedWUs.append(eptr - bptr, bptr);
  985. else
  986. queuedWUs.append(bptr);
  987. if (maxDisplay > items.length())
  988. {
  989. unsigned queueLen = atoi(queuedWUs.str());
  990. if (queueLen > longestQueue)
  991. longestQueue = queueLen;
  992. }
  993. tq->setQueuedWUs(queuedWUs.str());
  994. if(!eptr)
  995. {
  996. if (checkNewThorQueueItem(tq, showAll, items))
  997. items.append(*tq.getClear());
  998. return;
  999. }
  1000. //waiting
  1001. bptr = eptr + 1;
  1002. eptr = strchr(bptr, ',');
  1003. if(eptr)
  1004. waitingThors.append(eptr - bptr, bptr);
  1005. else
  1006. waitingThors.append(bptr);
  1007. tq->setWaitingThors(waitingThors.str());
  1008. if(!eptr)
  1009. {
  1010. if (checkNewThorQueueItem(tq, showAll, items))
  1011. items.append(*tq.getClear());
  1012. return;
  1013. }
  1014. //connected
  1015. bptr = eptr + 1;
  1016. eptr = strchr(bptr, ',');
  1017. if(eptr)
  1018. connectedThors.append(eptr - bptr, bptr);
  1019. else
  1020. connectedThors.append(bptr);
  1021. if (maxDisplay > items.length())
  1022. {
  1023. unsigned connnectedLen = atoi(connectedThors.str());
  1024. if (connnectedLen > maxConnected)
  1025. maxConnected = connnectedLen;
  1026. }
  1027. tq->setConnectedThors(connectedThors.str());
  1028. if(!eptr)
  1029. {
  1030. if (checkNewThorQueueItem(tq, showAll, items))
  1031. items.append(*tq.getClear());
  1032. return;
  1033. }
  1034. //idled
  1035. bptr = eptr + 1;
  1036. eptr = strchr(bptr, ',');
  1037. if(eptr)
  1038. idledThors.append(eptr - bptr, bptr);
  1039. else
  1040. idledThors.append(bptr);
  1041. tq->setIdledThors(idledThors.str());
  1042. if(!eptr)
  1043. {
  1044. items.append(*tq.getClear());
  1045. return;
  1046. }
  1047. //runningWU1
  1048. bptr = eptr + 1;
  1049. eptr = strchr(bptr, ',');
  1050. if(eptr)
  1051. runningWU1.append(eptr - bptr, bptr);
  1052. else
  1053. {
  1054. runningWU1.append(bptr);
  1055. }
  1056. if (!strcmp(runningWU1.str(), "---"))
  1057. runningWU1.clear();
  1058. if (runningWU1.length() > 0)
  1059. tq->setRunningWU1(runningWU1.str());
  1060. if(!eptr)
  1061. {
  1062. if (checkNewThorQueueItem(tq, showAll, items))
  1063. items.append(*tq.getClear());
  1064. return;
  1065. }
  1066. //runningWU2
  1067. bptr = eptr + 1;
  1068. eptr = strchr(bptr, ',');
  1069. if(eptr)
  1070. runningWU2.append(eptr - bptr, bptr);
  1071. else
  1072. {
  1073. runningWU2.append(bptr);
  1074. }
  1075. if (!strcmp(runningWU2.str(), "---"))
  1076. runningWU2.clear();
  1077. if (runningWU2.length() > 0)
  1078. tq->setRunningWU2(runningWU2.str());
  1079. if (checkNewThorQueueItem(tq, showAll, items))
  1080. items.append(*tq.getClear());
  1081. DBGLOG("Queue log: [%s]", line);
  1082. }
  1083. void streamJobQueueListResponse(IEspContext &context, const char *cluster, const char *from , const char *to, CHttpResponse* response, const char *xls)
  1084. {
  1085. if(!response)
  1086. return;
  1087. unsigned maxDisplay = 125;
  1088. IArrayOf<IEspThorQueue> items;
  1089. CDateTime fromTime;
  1090. StringBuffer fromstr;
  1091. if (notEmpty(from))
  1092. {
  1093. fromTime.setString(from, NULL, false);
  1094. fromTime.getString(fromstr, false);
  1095. }
  1096. CDateTime toTime;
  1097. StringBuffer tostr;
  1098. if(notEmpty(to))
  1099. {
  1100. toTime.setString(to,NULL,false);
  1101. toTime.getString(tostr, false);
  1102. }
  1103. StringBuffer filter("ThorQueueMonitor");
  1104. if (notEmpty(cluster))
  1105. filter.appendf(",%s", cluster);
  1106. StringAttrArray lines;
  1107. queryAuditLogs(fromTime, toTime, filter.str(), lines);
  1108. unsigned countLines = 0;
  1109. unsigned maxConnected = 0;
  1110. unsigned longestQueue = 0;
  1111. ForEachItemIn(idx, lines)
  1112. {
  1113. if(!lines.item(idx).text.length())
  1114. continue;
  1115. if (idx < (lines.length() - 1))
  1116. appendQueueInfoFromAuditLine(items, lines.item(idx).text.get(), longestQueue, maxConnected, maxDisplay, 1);
  1117. else
  1118. appendQueueInfoFromAuditLine(items, lines.item(idx).text.get(), longestQueue, maxConnected, maxDisplay, 2);
  1119. countLines++;
  1120. }
  1121. if (items.length() < 1)
  1122. {
  1123. response->sendChunk("<script language=\"javascript\">\r\nparent.displayQEnd(\'No data found\')</script>\r\n");
  1124. return;
  1125. }
  1126. unsigned itemCount = items.length();
  1127. if (itemCount > maxDisplay)
  1128. itemCount = maxDisplay;
  1129. StringBuffer sb;
  1130. sb.append("<script language=\"javascript\">parent.displayQLegend()</script>\r\n");
  1131. sb.append("<script language=\"javascript\">parent.displayQBegin(");
  1132. sb.append(longestQueue).append(',').append(maxConnected).append(',').append(itemCount).append(")</script>\r\n");
  1133. response->sendChunk(sb.str());
  1134. sb.clear().append("<script language=\"javascript\">\r\n");
  1135. unsigned count = 0;
  1136. unsigned sbcount=0;
  1137. ForEachItemIn(i,items)
  1138. {
  1139. IEspThorQueue& tq = items.item(i);
  1140. count++;
  1141. if (count > maxDisplay)
  1142. break;
  1143. sb.append("parent.displayQueue(");
  1144. appendQuoted(sb, count, true);
  1145. appendQuoted(sb, tq.getDT());
  1146. appendQuoted(sb, tq.getRunningWUs());
  1147. appendQuoted(sb, tq.getQueuedWUs());
  1148. appendQuoted(sb, tq.getWaitingThors());
  1149. appendQuoted(sb, tq.getConnectedThors());
  1150. appendQuoted(sb, tq.getIdledThors());
  1151. appendQuoted(sb, tq.getRunningWU1());
  1152. appendQuoted(sb, tq.getRunningWU2());
  1153. sb.append(")\r\n");
  1154. if(++sbcount>=50)
  1155. {
  1156. sb.append("</script>\r\n");
  1157. response->sendChunk(sb.str());
  1158. sb.clear().append("<script language=\"javascript\">\r\n");
  1159. sbcount=0;
  1160. }
  1161. }
  1162. sb.append("parent.displayQEnd(\'<table><tr><td>");
  1163. sb.append("Total Records in the Time Period: ").append(items.length());
  1164. sb.append(" (<a href=\"/WsWorkunits/WUClusterJobQueueLOG?").append(xls);
  1165. sb.append("\">txt</a>...<a href=\"/WsWorkunits/WUClusterJobQueueXLS?").append(xls).append("\">xls</a>).");
  1166. sb.append("</td></tr><tr><td>");
  1167. if (count > maxDisplay)
  1168. sb.append("Displayed: First ").append(maxDisplay).append(". ");
  1169. sb.append("Max. Queue Length: ").append(longestQueue).append(".");
  1170. sb.append("</td></tr></table>\')</script>\r\n");
  1171. response->sendChunk(sb.str());
  1172. }
  1173. int CWsWorkunitsSoapBindingEx::onGet(CHttpRequest* request, CHttpResponse* response)
  1174. {
  1175. IEspContext *ctx = request->queryContext();
  1176. IProperties *params = request->queryParameters();
  1177. try
  1178. {
  1179. StringBuffer path;
  1180. request->getPath(path);
  1181. if(!strnicmp(path.str(), "/WsWorkunits/JobList", 20))
  1182. {
  1183. const char *cluster = params->queryProp("Cluster");
  1184. const char *startDate = params->queryProp("StartDate");
  1185. const char *endDate = params->queryProp("EndDate");
  1186. const char *showAll = params->queryProp("ShowAll");
  1187. const char *busStart = params->queryProp("BusinessStartTime");
  1188. const char *busEnd = params->queryProp("BusinessEndTime");
  1189. float fBusStart = 0;
  1190. float fBusEnd = 24;
  1191. bool bShowAll = (isEmpty(showAll) ? false : (atoi(showAll)==1));
  1192. if (bShowAll)
  1193. {
  1194. timeStrToFloat(busStart, fBusStart);
  1195. timeStrToFloat(busEnd, fBusEnd);
  1196. if(fBusStart <= 0 || fBusEnd > 24 || fBusStart >= fBusEnd)
  1197. throw MakeStringException(ECLWATCH_INVALID_INPUT, "Invalid business hours");
  1198. }
  1199. response->addHeader("Expires", "0");
  1200. response->setContentType(HTTP_TYPE_TEXT_HTML_UTF8);
  1201. StringBuffer xls("ShowAll=1");
  1202. addToQueryString(xls, "Cluster", cluster);
  1203. addToQueryString(xls, "StartDate", startDate);
  1204. addToQueryString(xls, "EndDate", endDate);
  1205. addToQueryString(xls, "BusinessStartTime", busStart);
  1206. addToQueryString(xls, "BusinessEndTime", busEnd);
  1207. streamJobListResponse(*ctx, cluster, startDate, endDate, response, bShowAll, fBusStart, fBusEnd, xls.str());
  1208. return 0;
  1209. }
  1210. else if(!strnicmp(path.str(), "/WsWorkunits/JobQueue", 21))
  1211. {
  1212. const char *cluster = params->queryProp("Cluster");
  1213. const char *startDate = params->queryProp("StartDate");
  1214. const char *endDate = params->queryProp("EndDate");
  1215. response->addHeader("Expires", "0");
  1216. response->setContentType(HTTP_TYPE_TEXT_HTML_UTF8);
  1217. StringBuffer xls;
  1218. xls.append("ShowType=InGraph");
  1219. addToQueryString(xls, "Cluster", cluster);
  1220. addToQueryString(xls, "StartDate", startDate);
  1221. addToQueryString(xls, "EndDate", endDate);
  1222. streamJobQueueListResponse(*ctx, cluster, startDate, endDate, response, xls.str());
  1223. return 0;
  1224. }
  1225. }
  1226. catch(IException* e)
  1227. {
  1228. FORWARDEXCEPTION(*request->queryContext(), e, ECLWATCH_INTERNAL_ERROR);
  1229. }
  1230. return CWsWorkunitsSoapBinding::onGet(request,response);
  1231. }
  1232. bool CWsWorkunitsEx::onWUClusterJobQueueXLS(IEspContext &context, IEspWUClusterJobQueueXLSRequest &req, IEspWUClusterJobQueueXLSResponse &resp)
  1233. {
  1234. try
  1235. {
  1236. DBGLOG("WUClusterJobQueueXLS");
  1237. SecAccessFlags accessOwn;
  1238. SecAccessFlags accessOthers;
  1239. getUserWuAccessFlags(context, accessOwn, accessOthers, true);
  1240. StringBuffer xml("<WUResultExcel><Result>");
  1241. getClusterJobQueueXLS(xml, req.getCluster(), req.getStartDate(), req.getEndDate(), req.getShowType());
  1242. xml.append("</Result></WUResultExcel>");
  1243. Owned<IProperties> params(createProperties());
  1244. params->setProp("showCount",0);
  1245. StringBuffer xls;
  1246. xsltTransform(xml.str(), StringBuffer(getCFD()).append("./smc_xslt/result.xslt").str(), params, xls);
  1247. MemoryBuffer mb;
  1248. mb.setBuffer(xls.length(), (void*)xls.str());
  1249. resp.setResult(mb);
  1250. resp.setResult_mimetype("application/vnd.ms-excel");
  1251. }
  1252. catch(IException* e)
  1253. {
  1254. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1255. }
  1256. return true;
  1257. }
  1258. bool CWsWorkunitsEx::onWUClusterJobQueueLOG(IEspContext &context,IEspWUClusterJobQueueLOGRequest &req, IEspWUClusterJobQueueLOGResponse &resp)
  1259. {
  1260. try
  1261. {
  1262. DBGLOG("WUClusterJobQueueLOG");
  1263. SecAccessFlags accessOwn;
  1264. SecAccessFlags accessOthers;
  1265. getUserWuAccessFlags(context, accessOwn, accessOthers, true);
  1266. CDateTime fromTime;
  1267. if(notEmpty(req.getStartDate()))
  1268. fromTime.setString(req.getStartDate(), NULL, false);
  1269. CDateTime toTime;
  1270. if(notEmpty(req.getEndDate()))
  1271. toTime.setString(req.getEndDate(), NULL, false);
  1272. const char *cluster = req.getCluster();
  1273. StringBuffer filter("ThorQueueMonitor");
  1274. if (notEmpty(cluster))
  1275. filter.appendf(",%s", cluster);
  1276. StringAttrArray lines;
  1277. queryAuditLogs(fromTime, toTime, filter.str(), lines);
  1278. StringBuffer text;
  1279. ForEachItemIn(idx, lines)
  1280. {
  1281. if (lines.item(idx).text.isEmpty())
  1282. continue;
  1283. text.append(lines.item(idx).text.get()).append("\r\n");
  1284. if (text.length()>LOGFILESIZELIMIT)
  1285. {
  1286. text.appendf("... ...");
  1287. break;
  1288. }
  1289. }
  1290. MemoryBuffer mb;
  1291. mb.setBuffer(text.length(), (void*)text.str());
  1292. resp.setThefile(mb);
  1293. resp.setThefile_mimetype(HTTP_TYPE_TEXT_PLAIN);
  1294. }
  1295. catch(IException* e)
  1296. {
  1297. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1298. }
  1299. return true;
  1300. }
  1301. bool CWsWorkunitsEx::onWUJobList(IEspContext &context, IEspWUJobListRequest &req, IEspWUJobListResponse &resp)
  1302. {
  1303. return true;
  1304. }
  1305. bool CWsWorkunitsEx::onWUClusterJobXLS(IEspContext &context, IEspWUClusterJobXLSRequest &req, IEspWUClusterJobXLSResponse &resp)
  1306. {
  1307. try
  1308. {
  1309. DBGLOG("WUClusterJobXLS");
  1310. SecAccessFlags accessOwn;
  1311. SecAccessFlags accessOthers;
  1312. getUserWuAccessFlags(context, accessOwn, accessOthers, true);
  1313. StringBuffer xml("<WUResultExcel><Result>");
  1314. getClusterJobXLS(context.getClientVersion(), xml, req.getCluster(), req.getStartDate(), req.getEndDate(), req.getShowAll(), req.getBusinessStartTime(), req.getBusinessEndTime());
  1315. xml.append("</Result></WUResultExcel>");
  1316. Owned<IProperties> params(createProperties());
  1317. params->setProp("showCount",0);
  1318. StringBuffer xls;
  1319. xsltTransform(xml.str(), StringBuffer(getCFD()).append("./smc_xslt/result.xslt").str(), params, xls);
  1320. MemoryBuffer mb;
  1321. mb.setBuffer(xls.length(), (void*)xls.str());
  1322. resp.setResult(mb);
  1323. resp.setResult_mimetype("application/vnd.ms-excel");
  1324. }
  1325. catch(IException* e)
  1326. {
  1327. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1328. }
  1329. return true;
  1330. }
  1331. bool CWsWorkunitsEx::onWUClusterJobSummaryXLS(IEspContext &context, IEspWUClusterJobSummaryXLSRequest &req, IEspWUClusterJobSummaryXLSResponse &resp)
  1332. {
  1333. try
  1334. {
  1335. DBGLOG("WUClusterJobSummaryXLS");
  1336. SecAccessFlags accessOwn;
  1337. SecAccessFlags accessOthers;
  1338. getUserWuAccessFlags(context, accessOwn, accessOthers, true);
  1339. StringBuffer xml("<WUResultExcel><Result>");
  1340. getClusterJobSummaryXLS(context.getClientVersion(), xml, req.getCluster(), req.getStartDate(), req.getEndDate(), req.getShowAll(), req.getBusinessStartTime(), req.getBusinessEndTime());
  1341. xml.append("</Result></WUResultExcel>");
  1342. StringBuffer xls;
  1343. Owned<IProperties> params(createProperties());
  1344. params->setProp("showCount",0);
  1345. xsltTransform(xml.str(), StringBuffer(getCFD()).append("./smc_xslt/result.xslt").str(), params, xls);
  1346. MemoryBuffer mb;
  1347. mb.setBuffer(xls.length(), (void*)xls.str());
  1348. resp.setResult(mb);
  1349. resp.setResult_mimetype("application/vnd.ms-excel");
  1350. }
  1351. catch(IException* e)
  1352. {
  1353. FORWARDEXCEPTION(context, e, ECLWATCH_INTERNAL_ERROR);
  1354. }
  1355. return true;
  1356. }