stats.html 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. <script src="./script/useragent.js"></script>
  2. <div class="standardContainer">
  3. <div class="ui basic segment">
  4. <h2>Statistical Analysis</h2>
  5. <p>Statistic of your server in every aspects</p>
  6. </div>
  7. <div class="ui divider"></div>
  8. <div class="ui basic segment">
  9. <!-- Client Geolocation Analysis-->
  10. <h3>Visitors Countries</h3>
  11. <p>Distributions of visitors by country code. Access origin are estimated using open source GeoIP database and might not be accurate.</p>
  12. <div style="min-height: 400px;">
  13. <canvas id="stats_visitors"></canvas>
  14. </div>
  15. <div class="ui divider"></div>
  16. <!-- Client IP Analysis -->
  17. <div class="ui stackable grid">
  18. <div class="eight wide column">
  19. <h3>Requests IP Version</h3>
  20. <p>The version of Internet Protocol that the client is using. If the request client is pass through a DNS proxy like CloudFlare,
  21. the CloudFlare proxy server address will be filtered and only the first value in the RemoteAddress field will be analysised.</p>
  22. <div>
  23. <canvas id="stats_ipver"></canvas>
  24. </div>
  25. </div>
  26. <div class="eight wide column">
  27. <h3>Request Origins</h3>
  28. <p>Top 25 request origin sorted by request count</p>
  29. <div style="height: 500px; overflow-y: auto;">
  30. <table class="ui unstackable striped celled table">
  31. <thead>
  32. <tr>
  33. <th>Request Origin</th>
  34. <th>No of Requests</th>
  35. </tr></thead>
  36. <tbody id="stats_requestCountlist">
  37. </tbody>
  38. </table>
  39. </div>
  40. </div>
  41. </div>
  42. <div class="ui divider"></div>
  43. <!-- Client Device Analysis -->
  44. <div class="ui stackable grid">
  45. <div class="eight wide column">
  46. <h3>Client Devices</h3>
  47. <p>Device type analysis by its request interactions.The number of iteration count does not means the number unique device, as no cookie is used to track the devices identify.</p>
  48. <div>
  49. <canvas id="stats_device"></canvas>
  50. </div>
  51. </div>
  52. <div class="eight wide column">
  53. <h3>Client Browsers</h3>
  54. <p>The browsers where your client is using to visit your site</p>
  55. <div>
  56. <canvas id="stats_browsers"></canvas>
  57. </div>
  58. </div>
  59. </div>
  60. <div class="ui stackable grid">
  61. <div class="eight wide column">
  62. <h3>Client OS</h3>
  63. <p>The OS where your client is using. Estimated using the UserAgent header sent by the client browser while requesting a resources from one of your host.</p>
  64. <div>
  65. <canvas id="stats_OS"></canvas>
  66. </div>
  67. </div>
  68. <div class="eight wide column">
  69. <h3>OS Versions</h3>
  70. <p>The OS versions most commonly used by your site's visitors.</p>
  71. <div style="height: 500px; overflow-y: auto;">
  72. <table class="ui unstackable striped celled table">
  73. <thead>
  74. <tr>
  75. <th>OS Version</th>
  76. <th>Request Counts</th>
  77. <th>Percentage</th>
  78. </tr></thead>
  79. <tbody id="stats_OSVersionList">
  80. </tbody>
  81. </table>
  82. </div>
  83. </div>
  84. </div>
  85. </div>
  86. <button class="ui icon right floated basic button" onclick="initStatisticSummery();"><i class="green refresh icon"></i> Refresh</button>
  87. <br><br>
  88. </div>
  89. <script>
  90. function initStatisticSummery(){
  91. $.getJSON("./example.json", function(data){
  92. //Render visitor data
  93. renderVisitorChart(data.RequestOrigin);
  94. //Render IP versions
  95. renderIPVersionChart(data.RequestClientIp);
  96. //Render user agent analysis
  97. renderUserAgentCharts(data.UserAgent);
  98. });
  99. }
  100. initStatisticSummery();
  101. function renderUserAgentCharts(userAgentsEntries){
  102. let userAgents = Object.keys(userAgentsEntries);
  103. let requestCounts = Object.values(userAgentsEntries);
  104. let mobileUser = 0;
  105. let desktopUser = 0;
  106. let osTypes = {};
  107. let osVersion = {};
  108. let browserTypes = {};
  109. let totalRequestCounts = 0;
  110. requestCounts.forEach(function(rc){
  111. totalRequestCounts += rc;
  112. })
  113. //Building a statistic summary
  114. userAgents.forEach(function(thisUA){
  115. var uaInfo = parseUserAgent(thisUA);
  116. if (uaInfo.isMobile){
  117. mobileUser+=userAgentsEntries[thisUA];
  118. }else{
  119. desktopUser+=userAgentsEntries[thisUA];
  120. }
  121. let currentNo = osTypes[uaInfo.os];
  122. let osVersionKey = uaInfo.os + " " + uaInfo.version.split("_").join(".");
  123. if (currentNo == undefined){
  124. osTypes[uaInfo.os] = userAgentsEntries[thisUA];
  125. }else{
  126. osTypes[uaInfo.os] = currentNo + userAgentsEntries[thisUA];
  127. }
  128. let p = osVersion[osVersionKey];
  129. if (p == undefined){
  130. osVersion[osVersionKey] = userAgentsEntries[thisUA];
  131. }else{
  132. osVersion[osVersionKey] = p + userAgentsEntries[thisUA];
  133. }
  134. let browserTypeKey = uaInfo.browser;
  135. if (browserTypeKey.indexOf("//") >= 0){
  136. //This is a uncatergorize browser, mostly a bot
  137. browserTypeKey = "Bots";
  138. }else if (browserTypeKey == ""){
  139. //No information
  140. browserTypeKey = "Unknown";
  141. }
  142. let b = browserTypes[browserTypeKey];
  143. if (b == undefined){
  144. browserTypes[browserTypeKey] = userAgentsEntries[thisUA];
  145. }else{
  146. browserTypes[browserTypeKey] = b + userAgentsEntries[thisUA];
  147. }
  148. });
  149. //Create the device chart
  150. let deviceTypeChart = new Chart(document.getElementById("stats_device"), {
  151. type: 'pie',
  152. data: {
  153. labels: ['Desktop', 'Mobile'],
  154. datasets: [{
  155. data: [desktopUser, mobileUser],
  156. backgroundColor: ['#e56b5e', '#6eb9c1'],
  157. hoverBackgroundColor: ['#e56b5e', '#6eb9c1']
  158. }]
  159. },
  160. options: {
  161. responsive: true,
  162. maintainAspectRatio: false,
  163. }
  164. });
  165. //Create the OS chart
  166. let OSnames = [];
  167. let OSCounts = [];
  168. let OSColors = [];
  169. for (const [key, value] of Object.entries(osTypes)) {
  170. OSnames.push(key);
  171. OSCounts.push(value);
  172. OSColors.push(getOSColorCode(key));
  173. }
  174. let osTypeChart = new Chart(document.getElementById("stats_OS"), {
  175. type: 'pie',
  176. data: {
  177. labels: OSnames,
  178. datasets: [{
  179. data: OSCounts,
  180. backgroundColor: OSColors,
  181. hoverBackgroundColor: OSColors
  182. }]
  183. },
  184. options: {
  185. responsive: true,
  186. maintainAspectRatio: false,
  187. }
  188. });
  189. //Populate the OS version table
  190. let sortedOSVersion = Object.entries(osVersion).sort((a, b) => b[1] - a[1]);
  191. // Loop through the sorted data and populate the table
  192. for (let i = 0; i < sortedOSVersion.length; i++) {
  193. let osVersion = sortedOSVersion[i][0];
  194. let requestcount = abbreviateNumber(sortedOSVersion[i][1]);
  195. let percentage = (sortedOSVersion[i][1] / totalRequestCounts).toFixed(3);
  196. // Create a new row in the table
  197. let row = $("<tr>");
  198. // Add the OS version and percentage as columns in the row
  199. $("<td>").text(osVersion).appendTo(row);
  200. $("<td>").text(requestcount).appendTo(row);
  201. $("<td>").text(percentage + "%").appendTo(row);
  202. // Add the row to the table body
  203. $("#stats_OSVersionList").append(row);
  204. }
  205. //Create the browser charts
  206. let browserNames = [];
  207. let broserCounts = [];
  208. let browserColors = [];
  209. let sortedBrowserTypes = Object.entries(browserTypes).sort((a, b) => b[1] - a[1]);
  210. console.log(sortedBrowserTypes);
  211. sortedBrowserTypes.forEach(function(entry){
  212. browserNames.push(entry[0]);
  213. broserCounts.push(entry[1]);
  214. browserColors.push(generateColorFromHash(entry[0]));
  215. });
  216. let browserTypeChart = new Chart(document.getElementById("stats_browsers"), {
  217. type: 'pie',
  218. data: {
  219. labels: browserNames,
  220. datasets: [{
  221. data: broserCounts,
  222. backgroundColor: browserColors,
  223. hoverBackgroundColor: browserColors
  224. }]
  225. },
  226. options: {
  227. responsive: true,
  228. maintainAspectRatio: false,
  229. }
  230. });
  231. console.log(browserTypes);
  232. }
  233. //Generate the IPversion pie chart
  234. function renderIPVersionChart(RequestClientIp){
  235. let ipv4Count = Object.keys(RequestClientIp).filter(ip => ip.includes('.')).length;
  236. let ipv6Count = Object.keys(RequestClientIp).filter(ip => ip.includes(':')).length;
  237. let totalCount = ipv4Count + ipv6Count;
  238. let ipv4Percent = ((ipv4Count / totalCount) * 100).toFixed(2);
  239. let ipv6Percent = ((ipv6Count / totalCount) * 100).toFixed(2);
  240. // Create the chart data object
  241. let chartData = {
  242. labels: ['IPv4', 'IPv6'],
  243. datasets: [{
  244. data: [ipv4Percent, ipv6Percent],
  245. backgroundColor: ['#9295f0', '#bff092'],
  246. hoverBackgroundColor: ['#9295f0', '#bff092']
  247. }]
  248. };
  249. // Create the chart options object
  250. let ipvChartOption = {
  251. responsive: true,
  252. maintainAspectRatio: false,
  253. };
  254. // Create the pie chart
  255. let ipTypeChart = new Chart(document.getElementById("stats_ipver"), {
  256. type: 'pie',
  257. data: chartData,
  258. options: ipvChartOption
  259. });
  260. //Populate the request count table
  261. let requestCounts = Object.entries(RequestClientIp);
  262. // Sort the array by the value (count)
  263. requestCounts.sort((a, b) => b[1] - a[1]);
  264. // Select the table body and empty it
  265. let tableBody = $('#stats_requestCountlist');
  266. tableBody.empty();
  267. // Loop through the sorted array and add the top 25 requested IPs to the table
  268. for (let i = 0; i < 25 && i < requestCounts.length; i++) {
  269. let [ip, count] = requestCounts[i];
  270. let row = $('<tr>').appendTo(tableBody);
  271. $('<td style="word-break: break-all;">').text(ip).appendTo(row);
  272. $('<td>').text(count).appendTo(row);
  273. }
  274. }
  275. //Generate a fixed color code from string hash
  276. function generateColorFromHash(stringToHash){
  277. let hash = 0;
  278. for (let i = 0; i < stringToHash.length; i++) {
  279. hash = stringToHash.charCodeAt(i) + ((hash << 5) - hash);
  280. }
  281. const hue = hash % 300;
  282. const saturation = Math.floor(Math.random() * 20) + 70;
  283. const lightness = Math.floor(Math.random() * 20) + 60;
  284. return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
  285. }
  286. //Generate the visitor country pie chart
  287. function renderVisitorChart(visitorData){
  288. // Extract the labels and data from the visitor data object
  289. let labels = [];
  290. let data = Object.values(visitorData);
  291. Object.keys(visitorData).forEach(function(cc){
  292. if (cc == ""){
  293. labels.push("Local / Unknown")
  294. }else{
  295. labels.push(`${getCountryName(cc)} [${cc.toUpperCase()}]` );
  296. }
  297. });
  298. // Define the colors to be used in the pie chart
  299. let colors = [];
  300. labels.forEach(function(cc){
  301. colors.push(generateColorFromHash(cc));
  302. });
  303. // Create the chart data object
  304. let CCchartData = {
  305. labels: labels,
  306. datasets: [{
  307. data: data,
  308. backgroundColor: colors
  309. }]
  310. };
  311. // Create the chart options object
  312. let CCchartOptions = {
  313. responsive: true,
  314. maintainAspectRatio: false,
  315. };
  316. // Create the pie chart
  317. const visitorsChart = new Chart(document.getElementById("stats_visitors"), {
  318. type: 'pie',
  319. data: CCchartData,
  320. options: CCchartOptions
  321. });
  322. }
  323. </script>