Improve statistic generation to avoid time calculation on request for statistic information

Norore 8 months ago committed by aeris
parent 4914bf1764
commit 4826c679e8
  1. 27
      app/controllers/statistics_controller.rb
  2. 22
      app/javascript/js/stats/grades.js
  3. 34
      app/javascript/js/stats/index.js
  4. 1
      app/javascript/packs/application.js
  5. 2
      app/models/stat.rb
  6. 18
      app/views/statistics/index.html.erb
  7. 38
      bin/stats
  8. 3
      config/routes.rb
  9. 9
      db/migrate/20220326181216_create_stats.rb
  10. 23
      db/schema.rb

@ -1,30 +1,11 @@
class StatisticsController < ApplicationController
def index; end
def grade
@services = Analysis.where(service: params.fetch(:service))
TODAY = Date.today
def show
service = params.fetch :id
respond_to do |format|
format.html
format.json do
grades = Hash.new 0
@services.each do |service|
if (result = service.result)
result.each do |r|
next unless (grade = r['grade'])
grades[grade] += 1
end
end
end
json = {
grades: {
labels: grades.keys,
dataset: grades
}
}
json = Stat.find_by(name: "grades_for_#{service}", date: TODAY).dataset
render json: json, status: :ok
end
end

@ -2,13 +2,13 @@ document.addEventListener("DOMContentLoaded", () => {
let gradesChart = document.getElementById('gradesChart').getContext('2d')
let background = [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
]
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
]
let createGradesChart = new Chart(gradesChart, {
type: 'bar'
@ -24,12 +24,10 @@ document.addEventListener("DOMContentLoaded", () => {
}).then((response) => {
response.json().then((data) => {
if (response.status === 200) {
let grades = data["grades"]["dataset"]
createGradesChart.data.labels = data["grades"]["labels"]
createGradesChart.data.labels = data["labels"]
createGradesChart.data.datasets = [{
label: 'Count',
data: grades,
label: 'Number',
data: data["dataset"],
backgroundColor: background
}]
createGradesChart.update()

@ -0,0 +1,34 @@
document.addEventListener("DOMContentLoaded", () => {
let background = [
'#5cb85c',
'#8db457',
'#beb052',
'#f0ad4e',
'#e4804e',
'#d9534f',
'#bb3d39',
'#000'
]
for (const service of ["https", "smtp", "tls", "xmpp"]) {
const name = service.replace(/^\w/, c => c.toUpperCase())
console.info(`grades${name}Chart`)
const canvas = document.getElementById(`grades${name}Chart`).getContext('2d')
const chart = new Chart(canvas, {type: 'pie'})
fetch(`/statistics/${service}.json`).then((response) => {
if (response.status === 200) {
response.json().then((data) => {
chart.data.labels = Object.keys(data)
chart.data.datasets = [{
label: 'Number of request',
data: Object.values(data),
backgroundColor: background
}]
chart.update()
})
}
});
}
});

@ -3,4 +3,5 @@ import 'css/application'
import Chart from 'chart.js/auto'
global.Chart = Chart
import 'js/stats/index'
import 'js/stats/grades'

@ -0,0 +1,2 @@
class Stat < ApplicationRecord
end

@ -1,7 +1,15 @@
<h2>Statistiques par service</h2>
<div class="row">
<div class="col-4">
<h2>Requests per service</h2>
<ul class="list-unstyled">
<% %i[https smtp xmpp tls ssh].each do |service| %>
<li><%= link_to service, stats_grade_path(service) %> (<%= Analysis.where(service: service).count %> recherches)</li>
<canvas id="servicesChart" aria-label="Pie chart for number of requests per service" role="img"></canvas>
</div>
<% %i[https smtp tls xmpp].each do |s| %>
<div class="col-4">
<h2>Grades for service <%= s.to_s.upcase %></h2>
<canvas id="<%= "grades" + s.to_s.upcase_first + "Chart" %>" aria-label="Bar chart for number of grades for service <%= s.to_s.upcase %>" role="img"></canvas>
</div>
<% end %>
</ul>
</div>

@ -0,0 +1,38 @@
#!./bin/rails runner
TODAY = Date.today
# general stat
stat_name = "request_per_service"
services = Analysis.group(:service).order(service: :asc).count
json = {
labels: services.keys,
dataset: services.values
}
Stat.delete_by name: stat_name, date: TODAY
Stat.create!(
name: stat_name,
date: TODAY,
dataset: json
)
# grade per service for https, smtp, tls and xmpp
%i[https smtp tls xmpp].each do |service_name|
stat_name = "grades_for_" + service_name.to_s
services = Analysis.where(service: service_name, pending: false)
grades = %w[A+ A B C D E F G].collect { |g| [g, 0] }.to_h
services.each do |service|
if (result = service.result)
result.each do |r|
next unless (grade = r['grade'])
grades[grade] += 1 if grades.has_key?(grade)
end
end
end
Stat.delete_by name: stat_name, date: TODAY
Stat.create!(
name: stat_name,
date: TODAY,
dataset: grades
)
end

@ -16,8 +16,7 @@ Rails.application.routes.draw do
root 'site#index'
post '/' => 'site#check'
get 'statistics/', to: 'statistics#index', as: 'statisticts'
get 'statistics/grade/:service', to: 'statistics#grade', as: 'stats_grade'
resources :statistics, only: %i[index show]
get 'sites' => 'site#sites'

@ -0,0 +1,9 @@
class CreateStats < ActiveRecord::Migration[7.0]
def change
create_table :stats, id: :uuid do |t|
t.string :name
t.date :date
t.jsonb :dataset
end
end
end

@ -2,16 +2,15 @@
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
# This file is the source Rails uses to define your schema when running `bin/rails
# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
# be faster and is potentially less error prone than running all of your
# migrations from scratch. Old migrations may fail to apply correctly if those
# migrations use external dependencies or application code.
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[6.1].define(version: 2019_12_01_192510) do
ActiveRecord::Schema[7.0].define(version: 2022_03_26_181216) do
# These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto"
enable_extension "plpgsql"
@ -21,10 +20,16 @@ ActiveRecord::Schema[6.1].define(version: 2019_12_01_192510) do
t.string "host", null: false
t.boolean "pending", default: true, null: false
t.jsonb "result"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
t.jsonb "args"
t.index ["service", "host", "args"], name: "index_analyses_on_service_and_host_and_args", unique: true
end
create_table "stats", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.string "name"
t.date "date"
t.jsonb "dataset"
end
end

Loading…
Cancel
Save