mirror of
https://github.com/czhu12/canine.git
synced 2025-12-20 02:10:05 -06:00
added live reloading metrics
This commit is contained in:
4
Gemfile
4
Gemfile
@@ -95,3 +95,7 @@ gem "httparty", "~> 0.22.0"
|
||||
gem "redcarpet", "~> 3.6"
|
||||
|
||||
gem "rubyzip", "~> 2.3"
|
||||
|
||||
gem "chartkick", "~> 5.1"
|
||||
|
||||
gem "groupdate", "~> 6.5"
|
||||
|
||||
@@ -111,6 +111,7 @@ GEM
|
||||
rack-test (>= 0.6.3)
|
||||
regexp_parser (>= 1.5, < 3.0)
|
||||
xpath (~> 3.2)
|
||||
chartkick (5.1.2)
|
||||
chronic (0.10.2)
|
||||
chunky_png (1.4.0)
|
||||
coderay (1.1.3)
|
||||
@@ -177,6 +178,8 @@ GEM
|
||||
activerecord (>= 4.0.0)
|
||||
globalid (1.2.1)
|
||||
activesupport (>= 6.1)
|
||||
groupdate (6.5.1)
|
||||
activesupport (>= 7)
|
||||
hashdiff (1.0.1)
|
||||
hashie (5.0.0)
|
||||
http (5.2.0)
|
||||
@@ -518,11 +521,13 @@ DEPENDENCIES
|
||||
bootsnap
|
||||
brakeman
|
||||
capybara
|
||||
chartkick (~> 5.1)
|
||||
cssbundling-rails
|
||||
debug
|
||||
devise (~> 4.9)
|
||||
dotenv (~> 3.1)
|
||||
friendly_id (~> 5.4)
|
||||
groupdate (~> 6.5)
|
||||
httparty (~> 0.22.0)
|
||||
image_processing (~> 1.13)
|
||||
importmap-rails
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
web: bin/rails server -p 3000
|
||||
worker: bundle exec sidekiq
|
||||
js: yarn build --reload
|
||||
js: yarn build --watch
|
||||
css: bin/rails tailwindcss:watch
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
import ApexCharts from "apexcharts";
|
||||
const ORDERED_COLORS = [
|
||||
"#a25772",
|
||||
"#3e5eff"
|
||||
];
|
||||
|
||||
|
||||
class Apex {
|
||||
constructor(element, datasets) {
|
||||
this.element = element;
|
||||
this.datasets = datasets;
|
||||
this.xAxis = this.datasets.map(d => d.metrics.map(m => new Date(m.created_at))).flat().sort();
|
||||
}
|
||||
|
||||
options() {
|
||||
return {
|
||||
chart: {
|
||||
events: {
|
||||
mounted: (c) => c.windowResizeHandler(),
|
||||
},
|
||||
type: "line",
|
||||
height: 400,
|
||||
background: "transparent",
|
||||
toolbar: {
|
||||
show: true,
|
||||
tools: {
|
||||
download: true,
|
||||
zoom: false,
|
||||
zoomin: false,
|
||||
zoomout: false,
|
||||
pan: false,
|
||||
reset: false,
|
||||
},
|
||||
},
|
||||
group: "metrics",
|
||||
},
|
||||
theme: {
|
||||
mode: 'dark',
|
||||
},
|
||||
stroke: {
|
||||
width: 2,
|
||||
},
|
||||
xaxis: {
|
||||
categories: this.xAxis,
|
||||
},
|
||||
series: this.datasets.map((dataset) => {
|
||||
let data = dataset.metrics
|
||||
if (dataset.type === "size") {
|
||||
data = data.map(m => m.value)
|
||||
} else {
|
||||
data = data.map(m => m.value)
|
||||
}
|
||||
return {
|
||||
name: dataset.name,
|
||||
data,
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
createSeriesData(data, index) {
|
||||
return [{
|
||||
name: data.name,
|
||||
data: data.data,
|
||||
color: ORDERED_COLORS[index],
|
||||
}];
|
||||
}
|
||||
|
||||
render() {
|
||||
var chart = new ApexCharts(this.element, this.options());
|
||||
chart.render()
|
||||
return chart;
|
||||
}
|
||||
}
|
||||
export default Apex;
|
||||
@@ -12,4 +12,4 @@ require("@rails/ujs").start()
|
||||
|
||||
import './channels/**/*_channel.js'
|
||||
import "./controllers"
|
||||
import "./apex"
|
||||
import "chartkick/chart.js"
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import Apex from "../apex";
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
export default class extends Controller {
|
||||
static values = {
|
||||
dataset: Array,
|
||||
}
|
||||
|
||||
connect() {
|
||||
new Apex(this.element, this.datasetValue).render();
|
||||
}
|
||||
}
|
||||
21
app/javascript/controllers/refresh_turbo_frame_controller.js
Normal file
21
app/javascript/controllers/refresh_turbo_frame_controller.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import { Controller } from "@hotwired/stimulus"
|
||||
|
||||
export default class extends Controller {
|
||||
static values = {
|
||||
frequency: Number
|
||||
}
|
||||
|
||||
connect() {
|
||||
console.log(this.frequencyValue)
|
||||
this.refreshInterval = setInterval(() => {
|
||||
console.log("Updating src");
|
||||
this.element.setAttribute("src", window.location.href);
|
||||
}, this.frequencyValue)
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (this.refreshInterval) {
|
||||
clearInterval(this.refreshInterval)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,42 +6,46 @@ class K8::Metrics::Metrics
|
||||
nodes = K8::Metrics::Api::Node.ls(cluster)
|
||||
metrics = []
|
||||
nodes.each do |node|
|
||||
tags = [ "node:#{node.name}" ]
|
||||
metrics << {
|
||||
metric_type: :cpu,
|
||||
tags: [ node.name ],
|
||||
tags:,
|
||||
metadata: { cpu: node.cpu_cores }
|
||||
}
|
||||
metrics << {
|
||||
metric_type: :memory,
|
||||
tags: [ node.name ],
|
||||
tags:,
|
||||
metadata: { memory: node.used_memory }
|
||||
}
|
||||
metrics << {
|
||||
metric_type: :total_cpu,
|
||||
tags: [ node.name ],
|
||||
tags:,
|
||||
metadata: { total_cpu: node.total_cpu }
|
||||
}
|
||||
metrics << {
|
||||
metric_type: :total_memory,
|
||||
tags: [ node.name ],
|
||||
tags:,
|
||||
metadata: { total_memory: node.total_memory }
|
||||
}
|
||||
|
||||
node.namespaces.each do |namespace, pods|
|
||||
pods.each do |pod|
|
||||
tags = [ "node:#{node.name}", "namespace:#{namespace}", "pod:#{pod.name}" ]
|
||||
metrics << {
|
||||
metric_type: :cpu,
|
||||
tags: [ node.name, namespace, pod.name ],
|
||||
tags:,
|
||||
metadata: { cpu: pod.cpu }
|
||||
}
|
||||
metrics << {
|
||||
metric_type: :memory,
|
||||
tags: [ node.name, namespace, pod.name ],
|
||||
tags:,
|
||||
metadata: { memory: pod.memory }
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
cluster.metrics.create(attributes)
|
||||
metrics.each do |metric|
|
||||
cluster.metrics.create(**metric)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h2 class="font-medium"><%= title %></h2>
|
||||
<div data-controller="chart" data-chart-dataset-value="<%= dataset.to_json %>"></div>
|
||||
</div>
|
||||
</div>
|
||||
119
app/views/clusters/metrics/_live_metrics.html.erb
Normal file
119
app/views/clusters/metrics/_live_metrics.html.erb
Normal file
@@ -0,0 +1,119 @@
|
||||
<div>
|
||||
<div class="flex space-x-2">
|
||||
<div class="badge badge-success">• LIVE</div>
|
||||
<div class="text-sm text-gray-500">
|
||||
Updated at: <%= Time.now.strftime("%H:%M:%S") %>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table mt-2 rounded-box" id="order_table" data-component="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">Node Name</span>
|
||||
</th>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">CPU Cores</span>
|
||||
</th>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">
|
||||
CPU Usage
|
||||
</span>
|
||||
</th>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">
|
||||
Memory Capacity
|
||||
</span>
|
||||
</th>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">
|
||||
Memory Usage
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @nodes.each do |node| %>
|
||||
<tr class="cursor-pointer hover:bg-base-200/40">
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 truncate">
|
||||
<div class="font-medium">
|
||||
<%= node.name %>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="font-medium">
|
||||
<%= integer_to_size(node.total_cpu) %>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="font-medium">
|
||||
<%= node.cpu_percent %>%
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="font-medium">
|
||||
<%= integer_to_size(node.total_memory) %>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="font-medium">
|
||||
<%= node.memory_percent %>%
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="table mt-2 rounded-box" data-component="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">Namespace</span>
|
||||
</th>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">Pod Name</span>
|
||||
</th>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">CPU</span>
|
||||
</th>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">
|
||||
Memory
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @nodes.each do |node| %>
|
||||
<% node.namespaces.each do |namespace, pods| %>
|
||||
<% pods.each do |pod| %>
|
||||
<tr class="cursor-pointer hover:bg-base-200/40">
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 truncate font-medium">
|
||||
<%= namespace %>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 truncate font-medium">
|
||||
<%= pod.name %>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="font-medium">
|
||||
<%= pod.cpu %>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="font-medium">
|
||||
<%= integer_to_size(pod.memory) %>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -1,114 +1,6 @@
|
||||
<%= cluster_layout(@cluster) do %>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/apexcharts/3.53.0/apexcharts.min.js"></script>
|
||||
<table class="table mt-2 rounded-box" id="order_table" data-component="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">Node Name</span>
|
||||
</th>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">CPU Cores</span>
|
||||
</th>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">
|
||||
CPU Usage
|
||||
</span>
|
||||
</th>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">
|
||||
Memory Capacity
|
||||
</span>
|
||||
</th>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">
|
||||
Memory Usage
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @nodes.each do |node| %>
|
||||
<tr class="cursor-pointer hover:bg-base-200/40">
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 truncate">
|
||||
<div class="font-medium">
|
||||
<%= node.name %>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="font-medium">
|
||||
<%= integer_to_size(node.total_cpu) %>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="font-medium">
|
||||
<%= node.cpu_percent %>%
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="font-medium">
|
||||
<%= integer_to_size(node.total_memory) %>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="font-medium">
|
||||
<%= node.memory_percent %>%
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<%= turbo_frame_tag "metrics", data: { controller: "refresh-turbo-frame", "refresh-turbo-frame-frequency-value": 5000 } do %>
|
||||
<%= render "live_metrics" %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table class="table mt-2 rounded-box" data-component="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">Namespace</span>
|
||||
</th>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">Pod Name</span>
|
||||
</th>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">CPU</span>
|
||||
</th>
|
||||
<th>
|
||||
<span class="text-sm font-medium text-base-content/80">
|
||||
Memory
|
||||
</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @nodes.each do |node| %>
|
||||
<% node.namespaces.each do |namespace, pods| %>
|
||||
<% pods.each do |pod| %>
|
||||
<tr class="cursor-pointer hover:bg-base-200/40">
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 truncate font-medium">
|
||||
<%= namespace %>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center space-x-3 truncate font-medium">
|
||||
<%= pod.name %>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="font-medium">
|
||||
<%= pod.cpu %>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="font-medium">
|
||||
<%= integer_to_size(pod.memory) %>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<% end %>
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace :metrics do
|
||||
end
|
||||
|
||||
desc "Poll Kubernetes cluster metrics"
|
||||
task nodes: :environment do
|
||||
task fetch: :environment do
|
||||
Cluster.running.each do |cluster|
|
||||
nodes = K8::Metrics::Metrics.call(cluster)
|
||||
end
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"apexcharts": "^3.54.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"chart.js": "^4.4.6",
|
||||
"chartkick": "^5.0.1",
|
||||
"chokidar": "^4.0.1",
|
||||
"daisyui": "^4.12.10",
|
||||
"esbuild-rails": "^1.0.7",
|
||||
|
||||
31
yarn.lock
31
yarn.lock
@@ -210,6 +210,11 @@
|
||||
"@jridgewell/resolve-uri" "^3.1.0"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||
|
||||
"@kurkle/color@^0.3.0":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@kurkle/color/-/color-0.3.2.tgz#5acd38242e8bde4f9986e7913c8fdf49d3aa199f"
|
||||
integrity sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==
|
||||
|
||||
"@lit-labs/ssr-dom-shim@^1.0.0", "@lit-labs/ssr-dom-shim@^1.1.0":
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.1.tgz#2f3a8f1d688935c704dbc89132394a41029acbb8"
|
||||
@@ -449,6 +454,27 @@ caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001663:
|
||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz#1529a723505e429fdfd49532e9fc42273ba7fed7"
|
||||
integrity sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA==
|
||||
|
||||
chart.js@4, chart.js@^4.4.6:
|
||||
version "4.4.6"
|
||||
resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-4.4.6.tgz#da39b84ca752298270d4c0519675c7659936abec"
|
||||
integrity sha512-8Y406zevUPbbIBA/HRk33khEmQPk5+cxeflWE/2rx1NJsjVWMPw/9mSP9rxHP5eqi6LNoPBVMfZHxbwLSgldYA==
|
||||
dependencies:
|
||||
"@kurkle/color" "^0.3.0"
|
||||
|
||||
chartjs-adapter-date-fns@>=3:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-3.0.0.tgz#c25f63c7f317c1f96f9a7c44bd45eeedb8a478e5"
|
||||
integrity sha512-Rs3iEB3Q5pJ973J93OBTpnP7qoGwvq3nUnoMdtxO+9aoJof7UFcRbWcIDteXuYd1fgAvct/32T9qaLyLuZVwCg==
|
||||
|
||||
chartkick@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/chartkick/-/chartkick-5.0.1.tgz#f557ff8560f974343dc65c7fc34ce1e8326d8ee7"
|
||||
integrity sha512-4F3tWI3eBQgnjCYZIZ+fHOaJuNyxeyhDE2Tm+voOWB19hDjSJceys/spzN52DOn8bWepNESGXvPVTGU1jeFsbA==
|
||||
optionalDependencies:
|
||||
chart.js "4"
|
||||
chartjs-adapter-date-fns ">=3"
|
||||
date-fns ">=2"
|
||||
|
||||
chokidar@^3.3.0, chokidar@^3.5.2, chokidar@^3.5.3:
|
||||
version "3.6.0"
|
||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
|
||||
@@ -539,6 +565,11 @@ daisyui@^4.12.10:
|
||||
picocolors "^1"
|
||||
postcss-js "^4"
|
||||
|
||||
date-fns@>=2:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-4.1.0.tgz#64b3d83fff5aa80438f5b1a633c2e83b8a1c2d14"
|
||||
integrity sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==
|
||||
|
||||
debug@^4:
|
||||
version "4.3.7"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52"
|
||||
|
||||
Reference in New Issue
Block a user