| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <title>Download Statistics</title> |
| <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.16.0/d3.min.js"></script> |
| <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.18/c3.min.js"></script> |
| <link href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.18/c3.min.css" rel="stylesheet"/> |
| <style> |
| body { |
| font-family: sans-serif; |
| text-align: center; |
| } |
| .loader { |
| margin: 100px auto; |
| font-size: 25px; |
| width: 1em; |
| height: 1em; |
| border-radius: 50%; |
| position: relative; |
| text-indent: -9999em; |
| -webkit-animation: load5 1.1s infinite ease; |
| animation: load5 1.1s infinite ease; |
| -webkit-transform: translateZ(0); |
| -ms-transform: translateZ(0); |
| transform: translateZ(0); |
| } |
| @-webkit-keyframes load5 { |
| 0%, |
| 100% { |
| box-shadow: 0em -2.6em 0em 0em #122040, 1.8em -1.8em 0 0em rgba(18,32,64, 0.2), 2.5em 0em 0 0em rgba(18,32,64, 0.2), 1.75em 1.75em 0 0em rgba(18,32,64, 0.2), 0em 2.5em 0 0em rgba(18,32,64, 0.2), -1.8em 1.8em 0 0em rgba(18,32,64, 0.2), -2.6em 0em 0 0em rgba(18,32,64, 0.5), -1.8em -1.8em 0 0em rgba(18,32,64, 0.7); |
| } |
| 12.5% { |
| box-shadow: 0em -2.6em 0em 0em rgba(18,32,64, 0.7), 1.8em -1.8em 0 0em #122040, 2.5em 0em 0 0em rgba(18,32,64, 0.2), 1.75em 1.75em 0 0em rgba(18,32,64, 0.2), 0em 2.5em 0 0em rgba(18,32,64, 0.2), -1.8em 1.8em 0 0em rgba(18,32,64, 0.2), -2.6em 0em 0 0em rgba(18,32,64, 0.2), -1.8em -1.8em 0 0em rgba(18,32,64, 0.5); |
| } |
| 25% { |
| box-shadow: 0em -2.6em 0em 0em rgba(18,32,64, 0.5), 1.8em -1.8em 0 0em rgba(18,32,64, 0.7), 2.5em 0em 0 0em #122040, 1.75em 1.75em 0 0em rgba(18,32,64, 0.2), 0em 2.5em 0 0em rgba(18,32,64, 0.2), -1.8em 1.8em 0 0em rgba(18,32,64, 0.2), -2.6em 0em 0 0em rgba(18,32,64, 0.2), -1.8em -1.8em 0 0em rgba(18,32,64, 0.2); |
| } |
| 37.5% { |
| box-shadow: 0em -2.6em 0em 0em rgba(18,32,64, 0.2), 1.8em -1.8em 0 0em rgba(18,32,64, 0.5), 2.5em 0em 0 0em rgba(18,32,64, 0.7), 1.75em 1.75em 0 0em #122040, 0em 2.5em 0 0em rgba(18,32,64, 0.2), -1.8em 1.8em 0 0em rgba(18,32,64, 0.2), -2.6em 0em 0 0em rgba(18,32,64, 0.2), -1.8em -1.8em 0 0em rgba(18,32,64, 0.2); |
| } |
| 50% { |
| box-shadow: 0em -2.6em 0em 0em rgba(18,32,64, 0.2), 1.8em -1.8em 0 0em rgba(18,32,64, 0.2), 2.5em 0em 0 0em rgba(18,32,64, 0.5), 1.75em 1.75em 0 0em rgba(18,32,64, 0.7), 0em 2.5em 0 0em #122040, -1.8em 1.8em 0 0em rgba(18,32,64, 0.2), -2.6em 0em 0 0em rgba(18,32,64, 0.2), -1.8em -1.8em 0 0em rgba(18,32,64, 0.2); |
| } |
| 62.5% { |
| box-shadow: 0em -2.6em 0em 0em rgba(18,32,64, 0.2), 1.8em -1.8em 0 0em rgba(18,32,64, 0.2), 2.5em 0em 0 0em rgba(18,32,64, 0.2), 1.75em 1.75em 0 0em rgba(18,32,64, 0.5), 0em 2.5em 0 0em rgba(18,32,64, 0.7), -1.8em 1.8em 0 0em #122040, -2.6em 0em 0 0em rgba(18,32,64, 0.2), -1.8em -1.8em 0 0em rgba(18,32,64, 0.2); |
| } |
| 75% { |
| box-shadow: 0em -2.6em 0em 0em rgba(18,32,64, 0.2), 1.8em -1.8em 0 0em rgba(18,32,64, 0.2), 2.5em 0em 0 0em rgba(18,32,64, 0.2), 1.75em 1.75em 0 0em rgba(18,32,64, 0.2), 0em 2.5em 0 0em rgba(18,32,64, 0.5), -1.8em 1.8em 0 0em rgba(18,32,64, 0.7), -2.6em 0em 0 0em #122040, -1.8em -1.8em 0 0em rgba(18,32,64, 0.2); |
| } |
| 87.5% { |
| box-shadow: 0em -2.6em 0em 0em rgba(18,32,64, 0.2), 1.8em -1.8em 0 0em rgba(18,32,64, 0.2), 2.5em 0em 0 0em rgba(18,32,64, 0.2), 1.75em 1.75em 0 0em rgba(18,32,64, 0.2), 0em 2.5em 0 0em rgba(18,32,64, 0.2), -1.8em 1.8em 0 0em rgba(18,32,64, 0.5), -2.6em 0em 0 0em rgba(18,32,64, 0.7), -1.8em -1.8em 0 0em #122040; |
| } |
| } |
| @keyframes load5 { |
| 0%, |
| 100% { |
| box-shadow: 0em -2.6em 0em 0em #122040, 1.8em -1.8em 0 0em rgba(18,32,64, 0.2), 2.5em 0em 0 0em rgba(18,32,64, 0.2), 1.75em 1.75em 0 0em rgba(18,32,64, 0.2), 0em 2.5em 0 0em rgba(18,32,64, 0.2), -1.8em 1.8em 0 0em rgba(18,32,64, 0.2), -2.6em 0em 0 0em rgba(18,32,64, 0.5), -1.8em -1.8em 0 0em rgba(18,32,64, 0.7); |
| } |
| 12.5% { |
| box-shadow: 0em -2.6em 0em 0em rgba(18,32,64, 0.7), 1.8em -1.8em 0 0em #122040, 2.5em 0em 0 0em rgba(18,32,64, 0.2), 1.75em 1.75em 0 0em rgba(18,32,64, 0.2), 0em 2.5em 0 0em rgba(18,32,64, 0.2), -1.8em 1.8em 0 0em rgba(18,32,64, 0.2), -2.6em 0em 0 0em rgba(18,32,64, 0.2), -1.8em -1.8em 0 0em rgba(18,32,64, 0.5); |
| } |
| 25% { |
| box-shadow: 0em -2.6em 0em 0em rgba(18,32,64, 0.5), 1.8em -1.8em 0 0em rgba(18,32,64, 0.7), 2.5em 0em 0 0em #122040, 1.75em 1.75em 0 0em rgba(18,32,64, 0.2), 0em 2.5em 0 0em rgba(18,32,64, 0.2), -1.8em 1.8em 0 0em rgba(18,32,64, 0.2), -2.6em 0em 0 0em rgba(18,32,64, 0.2), -1.8em -1.8em 0 0em rgba(18,32,64, 0.2); |
| } |
| 37.5% { |
| box-shadow: 0em -2.6em 0em 0em rgba(18,32,64, 0.2), 1.8em -1.8em 0 0em rgba(18,32,64, 0.5), 2.5em 0em 0 0em rgba(18,32,64, 0.7), 1.75em 1.75em 0 0em #122040, 0em 2.5em 0 0em rgba(18,32,64, 0.2), -1.8em 1.8em 0 0em rgba(18,32,64, 0.2), -2.6em 0em 0 0em rgba(18,32,64, 0.2), -1.8em -1.8em 0 0em rgba(18,32,64, 0.2); |
| } |
| 50% { |
| box-shadow: 0em -2.6em 0em 0em rgba(18,32,64, 0.2), 1.8em -1.8em 0 0em rgba(18,32,64, 0.2), 2.5em 0em 0 0em rgba(18,32,64, 0.5), 1.75em 1.75em 0 0em rgba(18,32,64, 0.7), 0em 2.5em 0 0em #122040, -1.8em 1.8em 0 0em rgba(18,32,64, 0.2), -2.6em 0em 0 0em rgba(18,32,64, 0.2), -1.8em -1.8em 0 0em rgba(18,32,64, 0.2); |
| } |
| 62.5% { |
| box-shadow: 0em -2.6em 0em 0em rgba(18,32,64, 0.2), 1.8em -1.8em 0 0em rgba(18,32,64, 0.2), 2.5em 0em 0 0em rgba(18,32,64, 0.2), 1.75em 1.75em 0 0em rgba(18,32,64, 0.5), 0em 2.5em 0 0em rgba(18,32,64, 0.7), -1.8em 1.8em 0 0em #122040, -2.6em 0em 0 0em rgba(18,32,64, 0.2), -1.8em -1.8em 0 0em rgba(18,32,64, 0.2); |
| } |
| 75% { |
| box-shadow: 0em -2.6em 0em 0em rgba(18,32,64, 0.2), 1.8em -1.8em 0 0em rgba(18,32,64, 0.2), 2.5em 0em 0 0em rgba(18,32,64, 0.2), 1.75em 1.75em 0 0em rgba(18,32,64, 0.2), 0em 2.5em 0 0em rgba(18,32,64, 0.5), -1.8em 1.8em 0 0em rgba(18,32,64, 0.7), -2.6em 0em 0 0em #122040, -1.8em -1.8em 0 0em rgba(18,32,64, 0.2); |
| } |
| 87.5% { |
| box-shadow: 0em -2.6em 0em 0em rgba(18,32,64, 0.2), 1.8em -1.8em 0 0em rgba(18,32,64, 0.2), 2.5em 0em 0 0em rgba(18,32,64, 0.2), 1.75em 1.75em 0 0em rgba(18,32,64, 0.2), 0em 2.5em 0 0em rgba(18,32,64, 0.2), -1.8em 1.8em 0 0em rgba(18,32,64, 0.5), -2.6em 0em 0 0em rgba(18,32,64, 0.7), -1.8em -1.8em 0 0em #122040; |
| } |
| } |
| |
| </style> |
| </head> |
| <body> |
| |
| <div> |
| <b>Project or filename:</b> |
| <input type="text" id="project"> |
| <b>Timespan:</b> |
| <select id="duration"> |
| <option value="24h">Past day</option> |
| <option value="1w">Past week</option> |
| <option selected value="1M">Past month</option> |
| <option value="3M">Past quarter</option> |
| </select> |
| <input type="button" onclick="fetch_stats();" value="Fetch stats"/> |
| </div> |
| |
| <div id="stats" style="display: none;"> |
| |
| <h2>Downloads by Country</h2> |
| <div id="stats_chart_country"></div> |
| |
| <div style="width: 48%; display: inline-block;"> |
| <h2>Most downloaded files</h2> |
| <table id="table_requests_main"> |
| <thead> |
| <tr><th>Filename:</th><th>Downloads (unique IPs):</tr> |
| </thead> |
| <tbody id="table_requests"></tbody> |
| </table> |
| <hr/> |
| <h2>Most traffic</h2> |
| <table id="table_traffic_main"> |
| <thead> |
| <tr><th>Filename:</th><th>Traffic in bytes:</tr> |
| </thead> |
| <tbody id="table_traffic"></tbody> |
| </table> |
| </div> |
| </div> |
| |
| <div id="spinner" style="display: none;"> |
| <div class="loader"></div> |
| Fetching statistics... |
| </div> |
| |
| <script type="text/javascript"> |
| |
| Number.prototype.pretty = function(fix) { |
| if (fix) { |
| return String(this.toFixed(fix)).replace(/(\d)(?=(\d{3})+\.)/g, '$1,'); |
| } |
| return String(this.toFixed(0)).replace(/(\d)(?=(\d{3})+$)/g, '$1,'); |
| }; |
| |
| function draw_bars(columns, domains, key) { |
| let chart = c3.generate({ |
| bindto: '#stats_chart_' + key, |
| data: { |
| type: 'bar', |
| columns: columns |
| } |
| |
| }); |
| } |
| |
| |
| function draw_line(columns, key) { |
| let chart = c3.generate({ |
| bindto: '#stats_chart_' + key + '_all', |
| data: { |
| type: 'area-spline', |
| x: 'x', |
| xFormat: '%Y%m%d %t:%M', |
| columns: columns |
| }, |
| point: { |
| show: false |
| }, |
| axis: { |
| x: { |
| type: 'timeseries', |
| tick: { |
| format: '%Y-%m-%d %H:%M', |
| count: 12 |
| } |
| } |
| } |
| }); |
| } |
| |
| function draw_donut(columns, key) { |
| let chart = c3.generate({ |
| bindto: '#stats_chart_' + key, |
| data: { |
| type: 'donut', |
| columns: columns |
| }, |
| tooltip: { |
| format: { |
| title: function (d) { return d; }, |
| value: function (value, ratio, id) { |
| var format = d3.format(',') ; |
| return format(value); |
| } |
| } |
| } |
| }); |
| chart.resize({height: 500, width: 800}); |
| } |
| |
| |
| |
| |
| function compile_chart(js) { |
| let domains = []; |
| let timestamps = ['x']; |
| let timestamps_all = ['x']; |
| |
| let total_by_country = []; |
| for (let k in js.by_country) { |
| total_by_country.push([k,js.by_country[k]]); |
| } |
| draw_donut(total_by_country, 'country'); |
| |
| |
| // Most downloaded files |
| let tbl = document.getElementById('table_requests'); |
| tbl.textContent = ""; |
| let files_sorted = Object.keys(js.by_requests).sort((a,b) => js.by_requests[b]-js.by_requests[a]); |
| for (let k of files_sorted) { |
| let value = js.by_requests[k]; |
| let value_unique = js.by_requests_unique[k]; |
| let tr = document.createElement('tr'); |
| let td1 = document.createElement('td'); |
| let td2 = document.createElement('td'); |
| td1.innerText = k; |
| td1.style.textAlign = 'left'; |
| td2.innerText = `${value.pretty()} (${value_unique.pretty()})`; |
| td2.style.textAlign = 'right'; |
| tr.appendChild(td1); |
| tr.appendChild(td2); |
| tbl.appendChild(tr); |
| } |
| |
| // Most downloaded files |
| tbl = document.getElementById('table_traffic'); |
| tbl.textContent = ""; |
| files_sorted = Object.keys(js.by_bytes).sort((a,b) => js.by_bytes[b]-js.by_bytes[a]); |
| for (let k of files_sorted) { |
| let value = js.by_bytes[k]; |
| let tr = document.createElement('tr'); |
| let td1 = document.createElement('td'); |
| let td2 = document.createElement('td'); |
| td1.innerText = k; |
| td1.style.textAlign = 'left'; |
| td2.innerText = value.pretty(); |
| td2.style.textAlign = 'right'; |
| tr.appendChild(td1); |
| tr.appendChild(td2); |
| tbl.appendChild(tr); |
| } |
| |
| |
| document.getElementById('spinner').style.display = "none"; |
| document.getElementById('stats').style.display = "block"; |
| |
| |
| // draw_bars(columns, domains, key); |
| } |
| |
| |
| function fetch_stats() { |
| document.getElementById('stats').style.display = "none"; |
| document.getElementById('spinner').style.display = "block"; |
| let project = document.getElementById('project').value; |
| let duration = document.getElementById('duration').value; |
| fetch(`stats?project=${project}&duration=${duration}`) |
| .then(response => response.json()) |
| .then(data=> { |
| compile_chart(data); |
| }) |
| .catch(error => console.error(error)); |
| } |
| |
| </script> |
| |
| <hr/> |
| The source code for this stats page can be found at: <a href="https://github.com/apache/infrastructure-dlstats">https://github.com/apache/infrastructure-dlstats</a>. |
| </body> |
| </html> |