UsageStatistics_Page_View.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. jQuery(document).ready(function($) {
  2. var lastData;
  3. function load() {
  4. top_object = $('.ustats_top');
  5. $('.ustats_loading').removeClass('w3tc_hidden');
  6. $('.ustats_content').addClass('w3tc_hidden');
  7. $('.ustats_error').addClass('w3tc_none');
  8. $('.ustats_nodata').addClass('w3tc_none');
  9. $.getJSON(ajaxurl + '?action=w3tc_ajax&_wpnonce=' + w3tc_nonce +
  10. '&w3tc_action=ustats_get',
  11. function(data) {
  12. lastData = data;
  13. // show sections with data
  14. for (p in data) {
  15. var v = data[p];
  16. jQuery('.ustats_' + p).css('display', 'flex');
  17. }
  18. setValues(data, 'ustats_');
  19. if (data.period.seconds)
  20. $('.ustats_content').removeClass('w3tc_hidden');
  21. else
  22. $('.ustats_nodata').removeClass('w3tc_none');
  23. $('.ustats_loading').addClass('w3tc_hidden');
  24. setCharts(data);
  25. setRefresh(
  26. (data && data.period ? data.period.to_update_secs : 0));
  27. showMetaboxes();
  28. }
  29. ).fail(function() {
  30. $('.ustats_error').removeClass('w3tc_none');
  31. $('.ustats_content').addClass('w3tc_hidden');
  32. $('.ustats_loading').addClass('w3tc_hidden');
  33. });
  34. }
  35. //
  36. // chart commons
  37. //
  38. var chartOptions = {
  39. //aspectRatio: 4,
  40. maintainAspectRatio: false,
  41. animation: false,
  42. legend: false,
  43. scales: {
  44. yAxes: [{
  45. ticks: {
  46. beginAtZero: true
  47. }
  48. }]
  49. }
  50. };
  51. var chartDateLabels = [];
  52. var chartGraphValues = {};
  53. var charts = {};
  54. function setCharts(data) {
  55. // collect functors that prepare data for their own chart
  56. var processors = [];
  57. processors.push(setChartsPageCache());
  58. processors.push(setChartsDb());
  59. processors.push(setChartsOc());
  60. processors.push(setChartsPhp());
  61. processors.push(setChartsCpu());
  62. processors.push(setChartsWpdb());
  63. processors.push(setChartsAccessLog());
  64. processors.push(setChartsMemcached());
  65. processors.push(setChartsRedis());
  66. processors.push(setChartsApc());
  67. // prepare collections
  68. var columnsToCollect = [];
  69. for (var i = 0; i < processors.length; i++) {
  70. for (var id in processors[i].chartDatasets) {
  71. var datasets = [];
  72. for (var i2 = 0; i2 < processors[i].chartDatasets[id].length; i2++) {
  73. var datasetTemplate = processors[i].chartDatasets[id][i2];
  74. var dataColumnString;
  75. if (Array.isArray(datasetTemplate.dataColumn)) {
  76. dataColumnString = datasetTemplate.dataColumn.join('.');
  77. } else {
  78. dataColumnString = datasetTemplate.dataColumn;
  79. }
  80. chartGraphValues[dataColumnString] = [];
  81. columnsToCollect.push({
  82. target: dataColumnString,
  83. column: datasetTemplate.dataColumn
  84. });
  85. datasets.push({
  86. label: datasetTemplate.label,
  87. data: chartGraphValues[dataColumnString],
  88. backgroundColor: datasetTemplate.backgroundColor
  89. });
  90. }
  91. charts[id].data.datasets = datasets;
  92. }
  93. }
  94. // collect data for charts
  95. var history = data.history;
  96. chartDateLabels.length = 0;
  97. for (var i = 0; i < history.length; i++) {
  98. var historyItem = history[i];
  99. var dateFormatted = '';
  100. if (history[i].timestamp_start) {
  101. var d = new Date(parseInt(history[i].timestamp_start) * 1000);
  102. dateFormatted = dateFormat(d);
  103. }
  104. chartDateLabels.push(dateFormatted);
  105. // custom preprocess history row
  106. for (var i2 = 0; i2 < processors.length; i2++) {
  107. if (processors[i2].preprocess) {
  108. processors[i2].preprocess(historyItem);
  109. }
  110. }
  111. // collect metrics for graphs
  112. for (var i2 = 0; i2 < columnsToCollect.length; i2++) {
  113. var c = columnsToCollect[i2];
  114. var v;
  115. if (Array.isArray(c.column)) {
  116. if (v = historyItem[c.column[0]]) {
  117. v = historyItem[c.column[0]][c.column[1]];
  118. }
  119. } else {
  120. v = historyItem[c.column];
  121. }
  122. chartGraphValues[c.target].push(v);
  123. }
  124. }
  125. // visualize
  126. for (var c in charts) {
  127. charts[c].update();
  128. }
  129. }
  130. $('.w3tcus_chart_check').click(function() {
  131. setCharts(lastData);
  132. });
  133. //
  134. // PageCache chart
  135. //
  136. function setChartsPageCache() {
  137. if (!charts['pagecache']) {
  138. var ctx = $('#w3tcus_pagecache_chart');
  139. charts['pagecache'] = new Chart(ctx, {
  140. type: 'bar',
  141. data: {
  142. labels: chartDateLabels,
  143. },
  144. options: chartOptions
  145. });
  146. }
  147. return {
  148. chartDatasets: {
  149. pagecache: [{
  150. label: 'Time (ms)',
  151. dataColumn: 'pagecache_requests_time_ms',
  152. backgroundColor: '#0073aa'
  153. }
  154. ]
  155. },
  156. preprocess: function(historyItem) {
  157. v = 0;
  158. if (historyItem.pagecache_requests_time_10ms && historyItem.php_requests) {
  159. v = ((historyItem.pagecache_requests_time_10ms * 10) /
  160. historyItem.php_requests).toFixed(0);
  161. }
  162. historyItem.pagecache_requests_time_ms = v;
  163. }
  164. };
  165. }
  166. //
  167. // Database chart
  168. //
  169. function setChartsDb() {
  170. if (!charts['db']) {
  171. var ctx = $('#w3tcus_dbcache_chart');
  172. charts['db'] = new Chart(ctx, {
  173. type: 'bar',
  174. data: {
  175. labels: chartDateLabels,
  176. },
  177. options: chartOptions
  178. });
  179. var ctx = $('#w3tcus_dbcache_time_chart');
  180. charts['db_time'] = new Chart(ctx, {
  181. type: 'bar',
  182. data: {
  183. labels: chartDateLabels,
  184. },
  185. options: chartOptions
  186. });
  187. }
  188. return {
  189. chartDatasets: {
  190. db_time: [{
  191. label: 'Time (ms)',
  192. dataColumn: 'dbcache_time_ms',
  193. backgroundColor: '#0073aa'
  194. }
  195. ],
  196. db: [{
  197. label: 'Calls',
  198. dataColumn: 'dbcache_calls_total',
  199. backgroundColor: '#0073aa'
  200. }, {
  201. label: 'Hits',
  202. dataColumn: 'dbcache_calls_hits',
  203. backgroundColor: 'green'
  204. }
  205. ]
  206. }
  207. };
  208. }
  209. //
  210. // OC chart
  211. //
  212. function setChartsOc(data) {
  213. if (!charts['oc']) {
  214. var ctx = $('#w3tcus_objectcache_chart');
  215. charts['oc'] = new Chart(ctx, {
  216. type: 'bar',
  217. data: {
  218. labels: chartDateLabels
  219. },
  220. options: chartOptions
  221. });
  222. var ctx = $('#w3tcus_objectcache_time_chart');
  223. charts['oc_time'] = new Chart(ctx, {
  224. type: 'bar',
  225. data: {
  226. labels: chartDateLabels
  227. },
  228. options: chartOptions
  229. });
  230. }
  231. return {
  232. chartDatasets: {
  233. oc_time: [{
  234. label: 'Time (ms)',
  235. dataColumn: 'objectcache_time_ms',
  236. backgroundColor: '#0073aa'
  237. }
  238. ],
  239. oc: [{
  240. label: 'Gets',
  241. dataColumn: 'objectcache_get_total',
  242. backgroundColor: '#0073aa'
  243. }, {
  244. label: 'Hits',
  245. dataColumn: 'objectcache_get_hits',
  246. backgroundColor: 'green'
  247. }, {
  248. label: 'Sets',
  249. dataColumn: 'objectcache_sets',
  250. backgroundColor: 'red'
  251. }
  252. ]
  253. }
  254. };
  255. }
  256. //
  257. // PHP chart
  258. //
  259. function setChartsPhp(data) {
  260. if (!charts['phpMemory']) {
  261. var ctx = $('#w3tcus_php_memory_chart');
  262. charts['phpMemory'] = new Chart(ctx, {
  263. type: 'bar',
  264. data: {
  265. labels: chartDateLabels,
  266. },
  267. options: chartOptions
  268. });
  269. }
  270. if (!charts['phpRequests']) {
  271. var ctx = $('#w3tcus_php_requests_chart');
  272. charts['phpRequests'] = new Chart(ctx, {
  273. type: 'bar',
  274. data: {
  275. labels: chartDateLabels
  276. },
  277. options: chartOptions
  278. });
  279. }
  280. var phpRequestsDatasets = [];
  281. $('.w3tcus_chart_check').each(function() {
  282. if ($(this).is(':checked')) {
  283. var dataColumn = $(this).data('column');
  284. var backgroundColor = $(this).data('background');
  285. if (!backgroundColor) {
  286. backgroundColor = '#0073aa';
  287. }
  288. if (startsWith(dataColumn, 'php_php_requests')) {
  289. phpRequestsDatasets.push({
  290. label: $(this).data('name'),
  291. dataColumn: dataColumn.substr(4),
  292. backgroundColor: backgroundColor
  293. });
  294. }
  295. }
  296. });
  297. return {
  298. chartDatasets: {
  299. phpMemory: [{
  300. label: 'MB',
  301. dataColumn: 'php_memory_mb',
  302. backgroundColor: '#0073aa'
  303. }
  304. ],
  305. phpRequests: phpRequestsDatasets
  306. },
  307. preprocess: function(historyItem) {
  308. var v = 0;
  309. if (historyItem.php_requests) {
  310. v = (historyItem.php_memory_100kb / 100.0 / historyItem.php_requests).toFixed(2)
  311. }
  312. historyItem.php_memory_mb = v;
  313. historyItem.php_requests_pagecache_miss =
  314. historyItem.php_requests - historyItem.php_requests_pagecache_hit;
  315. }
  316. };
  317. }
  318. //
  319. // CPU chart
  320. //
  321. function setChartsCpu(data) {
  322. if (!charts['cpu']) {
  323. var ctx = $('#w3tcus_cpu_chart');
  324. charts['cpu'] = new Chart(ctx, {
  325. type: 'bar',
  326. data: {
  327. labels: chartDateLabels,
  328. },
  329. options: chartOptions
  330. });
  331. }
  332. return {
  333. chartDatasets: {
  334. cpu: [{
  335. label: 'CPU',
  336. dataColumn: 'cpu',
  337. backgroundColor: '#0073aa'
  338. }
  339. ]
  340. }
  341. };
  342. }
  343. //
  344. // WPDB chart
  345. //
  346. function setChartsWpdb(data) {
  347. if (!charts['wpdb']) {
  348. var ctx = $('#w3tcus_wpdb_chart');
  349. charts['wpdb'] = new Chart(ctx, {
  350. type: 'bar',
  351. data: {
  352. labels: chartDateLabels,
  353. },
  354. options: chartOptions
  355. });
  356. }
  357. return {
  358. chartDatasets: {
  359. wpdb: [{
  360. label: 'Total',
  361. dataColumn: 'wpdb_calls_total',
  362. backgroundColor: '#0073aa'
  363. }]
  364. }
  365. };
  366. }
  367. //
  368. // Access Log chart
  369. //
  370. function setChartsAccessLog(data) {
  371. if (!charts['accessLogRequests']) {
  372. var ctx = $('#w3tcus_access_log_chart_requests');
  373. charts['accessLogRequests'] = new Chart(ctx, {
  374. type: 'bar',
  375. data: {
  376. labels: chartDateLabels,
  377. },
  378. options: chartOptions
  379. });
  380. }
  381. if (!charts['accessLogTiming']) {
  382. var ctx = $('#w3tcus_access_log_chart_timing');
  383. charts['accessLogTiming'] = new Chart(ctx, {
  384. type: 'bar',
  385. data: {
  386. labels: chartDateLabels
  387. },
  388. options: chartOptions
  389. });
  390. }
  391. return {
  392. chartDatasets: {
  393. accessLogRequests: [{
  394. label: 'Dynamic',
  395. dataColumn: ['access_log', 'dynamic_count'],
  396. backgroundColor: '#0073aa'
  397. }, {
  398. label: 'Static',
  399. dataColumn: ['access_log', 'static_count'],
  400. backgroundColor: '#0073aa'
  401. }
  402. ],
  403. accessLogTiming: [{
  404. label: 'Dynamic',
  405. dataColumn: ['access_log', 'dynamic_timing'],
  406. backgroundColor: '#0073aa'
  407. }, {
  408. label: 'Static',
  409. dataColumn: ['access_log', 'static_timing'],
  410. backgroundColor: '#0073aa'
  411. }
  412. ]
  413. },
  414. preprocess: function(historyItem) {
  415. var dc = 0, sc = 0, dt = 0, st = 0;
  416. if (historyItem.access_log) {
  417. var a = historyItem.access_log;
  418. dc = a.dynamic_count;
  419. if (dc) {
  420. dt = (a.dynamic_timetaken_ms / dc).toFixed(2);
  421. }
  422. sc = a.static_count;
  423. if (sc) {
  424. st = (a.static_timetaken_ms / dc).toFixed(2);
  425. }
  426. historyItem['access_log']['dynamic_timing'] = dt;
  427. historyItem['access_log']['static_timing'] = st;
  428. }
  429. }
  430. };
  431. }
  432. //
  433. // Memcached chart
  434. //
  435. function setChartsMemcached(data) {
  436. if (!charts['memcachedSize']) {
  437. var ctx = $('#w3tcus_memcached_size_chart');
  438. charts['memcachedSize'] = new Chart(ctx, {
  439. type: 'bar',
  440. data: {
  441. labels: chartDateLabels
  442. },
  443. options: chartOptions
  444. });
  445. }
  446. if (!charts['memcachedHit']) {
  447. var ctx = $('#w3tcus_memcached_hit_chart');
  448. charts['memcachedHit'] = new Chart(ctx, {
  449. type: 'bar',
  450. data: {
  451. labels: chartDateLabels
  452. },
  453. options: chartOptions
  454. });
  455. }
  456. var prevCalls = -1;
  457. var prevHits = -1;
  458. return {
  459. chartDatasets: {
  460. memcachedSize: [{
  461. label: 'MB',
  462. dataColumn: 'memcached_size_mb',
  463. backgroundColor: '#0073aa'
  464. }],
  465. memcachedHit: [{
  466. label: 'Calls',
  467. dataColumn: 'memcached_requests_total',
  468. backgroundColor: '#0073aa'
  469. }, {
  470. label: 'Hits',
  471. dataColumn: 'memcached_requests_hits',
  472. backgroundColor: 'green'
  473. }
  474. ]
  475. },
  476. preprocess: function(historyItem) {
  477. var size = 0;
  478. var calls = 0;
  479. var hits = 0;
  480. if (historyItem.memcached && historyItem.memcached.size_used) {
  481. size = (historyItem.memcached.size_used / 1024.0 / 1024.0).toFixed(2);
  482. if (prevCalls >= 0 && historyItem.memcached.get_calls >= prevCalls) {
  483. calls = historyItem.memcached.get_calls - prevCalls;
  484. hits = historyItem.memcached.get_hits - prevHits;
  485. }
  486. if (calls > 10000) {
  487. calls = 0;
  488. hits = 0;
  489. }
  490. prevCalls = historyItem.memcached.get_calls;
  491. prevHits = historyItem.memcached.get_hits;
  492. }
  493. historyItem.memcached_size_mb = size;
  494. historyItem.memcached_requests_total = calls;
  495. historyItem.memcached_requests_hits = hits;
  496. }
  497. };
  498. }
  499. //
  500. // Redis chart
  501. //
  502. function setChartsRedis(data) {
  503. if (!charts['redisSize']) {
  504. var ctx = $('#w3tcus_redis_size_chart');
  505. charts['redisSize'] = new Chart(ctx, {
  506. type: 'bar',
  507. data: {
  508. labels: chartDateLabels
  509. },
  510. options: chartOptions
  511. });
  512. }
  513. if (!charts['redisHit']) {
  514. var ctx = $('#w3tcus_redis_hit_chart');
  515. charts['redisHit'] = new Chart(ctx, {
  516. type: 'bar',
  517. data: {
  518. labels: chartDateLabels
  519. },
  520. options: chartOptions
  521. });
  522. }
  523. var prevCalls = -1;
  524. var prevHits = -1;
  525. return {
  526. chartDatasets: {
  527. redisSize: [{
  528. label: 'MB',
  529. dataColumn: 'redis_size_mb',
  530. backgroundColor: '#0073aa'
  531. }],
  532. redisHit: [{
  533. label: 'Calls',
  534. dataColumn: 'redis_requests_total',
  535. backgroundColor: '#0073aa'
  536. }, {
  537. label: 'Hits',
  538. dataColumn: 'redis_requests_hits',
  539. backgroundColor: 'green'
  540. }
  541. ]
  542. },
  543. preprocess: function(historyItem) {
  544. var size = 0;
  545. var calls = 0;
  546. var hits = 0;
  547. if (historyItem.redis && historyItem.redis.size_used) {
  548. size = (historyItem.redis.size_used / 1024.0 / 1024.0).toFixed(2);
  549. if (prevCalls >= 0 && historyItem.redis.get_calls >= prevCalls) {
  550. calls = historyItem.redis.get_calls - prevCalls;
  551. hits = historyItem.redis.get_hits - prevHits;
  552. }
  553. if (calls > 10000) {
  554. calls = 0;
  555. hits = 0;
  556. }
  557. prevCalls = historyItem.redis.get_calls;
  558. prevHits = historyItem.redis.get_hits;
  559. }
  560. historyItem.redis_size_mb = size;
  561. historyItem.redis_requests_total = calls;
  562. historyItem.redis_requests_hits = hits;
  563. }
  564. };
  565. }
  566. //
  567. // APC chart
  568. //
  569. function setChartsApc(data) {
  570. if (!charts['apcSize']) {
  571. var ctx = $('#w3tcus_apc_size_chart');
  572. charts['apcSize'] = new Chart(ctx, {
  573. type: 'bar',
  574. data: {
  575. labels: chartDateLabels
  576. },
  577. options: chartOptions
  578. });
  579. }
  580. if (!charts['apcHit']) {
  581. var ctx = $('#w3tcus_apc_hit_chart');
  582. charts['apcHit'] = new Chart(ctx, {
  583. type: 'bar',
  584. data: {
  585. labels: chartDateLabels
  586. },
  587. options: chartOptions
  588. });
  589. }
  590. var prevCalls = -1;
  591. var prevHits = -1;
  592. return {
  593. chartDatasets: {
  594. apcSize: [{
  595. label: 'MB',
  596. dataColumn: 'apc_size_mb',
  597. backgroundColor: '#0073aa'
  598. }],
  599. apcHit: [{
  600. label: 'Calls',
  601. dataColumn: 'apc_requests_total',
  602. backgroundColor: '#0073aa'
  603. }, {
  604. label: 'Hits',
  605. dataColumn: 'apc_requests_hits',
  606. backgroundColor: 'green'
  607. }
  608. ]
  609. },
  610. preprocess: function(historyItem) {
  611. var size = 0;
  612. var calls = 0;
  613. var hits = 0;
  614. if (historyItem.apc && historyItem.apc.size_used) {
  615. size = (historyItem.apc.size_used / 1024.0 / 1024.0).toFixed(2);
  616. if (prevCalls >= 0 && historyItem.apc.get_total >= prevCalls) {
  617. calls = historyItem.apc.get_total - prevCalls;
  618. hits = historyItem.apc.get_hits - prevHits;
  619. }
  620. if (calls > 10000) {
  621. calls = 0;
  622. hits = 0;
  623. }
  624. prevCalls = historyItem.apc.get_total;
  625. prevHits = historyItem.apc.get_hits;
  626. }
  627. historyItem.apc_size_mb = size;
  628. historyItem.apc_requests_total = calls;
  629. historyItem.apc_requests_hits = hits;
  630. }
  631. };
  632. }
  633. //
  634. // Utils
  635. //
  636. function startsWith(s, prefix) {
  637. return s && s.substr(0, prefix.length) == prefix;
  638. }
  639. function dateFormat(d) {
  640. return ("0" + d.getUTCHours()).slice(-2) + ":" +
  641. ("0" + d.getUTCMinutes()).slice(-2);
  642. }
  643. function setValues(data, css_class_prefix) {
  644. for (p in data) {
  645. var v = data[p];
  646. if (typeof(v) != 'string' && typeof(v) != 'number')
  647. setValues(v, css_class_prefix + p + '_');
  648. else {
  649. jQuery('.' + css_class_prefix + p + ' span').html(v);
  650. if (jQuery('.' + css_class_prefix + p).hasClass('w3tcus_inline')) {
  651. jQuery('.' + css_class_prefix + p).css('display', 'inline');
  652. } else {
  653. jQuery('.' + css_class_prefix + p).css('display', 'block');
  654. }
  655. }
  656. }
  657. }
  658. var seconds_timer_id;
  659. function setRefresh(new_seconds_till_refresh) {
  660. clearTimeout(seconds_timer_id);
  661. var seconds_till_refresh = new_seconds_till_refresh;
  662. seconds_timer_id = setInterval(function() {
  663. seconds_till_refresh--;
  664. if (seconds_till_refresh <= 0) {
  665. clearTimeout(seconds_timer_id);
  666. seconds_timer_id = null;
  667. load();
  668. return;
  669. }
  670. jQuery('.ustats_reload').text('Will be recalculated in ' +
  671. seconds_till_refresh + ' second' +
  672. (seconds_till_refresh > 1 ? 's' : ''));
  673. }, 1000);
  674. }
  675. function showMetaboxes() {
  676. jQuery('.metabox-holder').each(function() {
  677. var visible = false;
  678. jQuery(this).find('.ustats_block').each(function() {
  679. visible |= jQuery(this).css('display') != 'none';
  680. });
  681. jQuery(this).css('display', (visible ? '' : 'none'));
  682. });
  683. }
  684. //
  685. // Main entry
  686. //
  687. load();
  688. $('.ustats_reload').click(function(e) {
  689. event.preventDefault();
  690. load();
  691. })
  692. });