Skip to content

Commit

Permalink
Merge pull request #30 from PhoenixNazarov/dev-healthcheck
Browse files Browse the repository at this point in the history
Dev healthcheck
  • Loading branch information
PhoenixNazarov authored Oct 23, 2024
2 parents d8a5d78 + a051758 commit ebd4596
Show file tree
Hide file tree
Showing 11 changed files with 227 additions and 74 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [Add widget for moderate users permissions](https://github.com/PhoenixNazarov/prompt-admin/pull/25)
- [Create HealthCheck status system](https://github.com/PhoenixNazarov/prompt-admin/pull/27)
- [Upgrade status time react, add description](https://github.com/PhoenixNazarov/prompt-admin/pull/27)
- Update design: Add borders, add resizable
- Add Charts for healthCheck

### Changed

Expand All @@ -47,3 +49,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fix start loading a list table component without a filter
- Bugfix load popup tables, back home, ident for test_case
- [Fix /auth/me return user password, now return password: null](https://github.com/PhoenixNazarov/prompt-admin/pull/25)
- Fix health check, add timezone
18 changes: 14 additions & 4 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"ajv-errors": "^3.0.0",
"ajv-formats": "^3.0.1",
"axios": "==1.7.4",
"chart.js": "^4.4.4",
"chart.js": "^4.4.5",
"chartjs-adapter-moment": "^1.0.1",
"dedent": "^1.5.3",
"json-editor-vue": "^0.15.1",
"moment": "^2.30.1",
Expand Down
2 changes: 2 additions & 0 deletions client/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {installFortAwesome} from "./plugins/fortawesome.ts";
import {installVuetify} from "./plugins/vuetify.ts";
import {installRouter} from "./plugins/router.ts";
import {installPrimevue} from "./plugins/primevue.ts";
import {installChartJs} from "./plugins/chartjs.ts";


const app = createApp(App)
Expand All @@ -18,6 +19,7 @@ installFortAwesome(app)
installVuetify(app)
installRouter(app)
installPrimevue(app)
installChartJs(app)


// Mount
Expand Down
20 changes: 20 additions & 0 deletions client/src/plugins/chartjs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {
BarElement,
CategoryScale,
Chart as ChartJS,
Legend,
LinearScale,
LineElement,
LogarithmicScale,
PointElement,
TimeScale,
Title,
Tooltip
} from 'chart.js'
import type {App} from "vue";
import 'chartjs-adapter-moment';

export function installChartJs(app: App) {
ChartJS.register(Title, Tooltip, Legend, BarElement, CategoryScale, LinearScale, TimeScale, LogarithmicScale, LineElement, PointElement)
}

20 changes: 11 additions & 9 deletions client/src/views/HealthCheck/HealthCheckView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,18 @@ export default defineComponent({
</script>

<template>
<VContainer>
<VCard>
<VCardTitle>Health Monitor</VCardTitle>
<VCardText>
<VSkeletonLoader type="card" v-if="healthCheckStore.loadings.targets"/>
<div class="outer-y" style="height: calc(100vh - 3rem)">
<VContainer>
<VCard>
<VCardTitle>Health Monitor</VCardTitle>
<VCardText>
<VSkeletonLoader type="card" v-if="healthCheckStore.loadings.targets"/>

<HealthTargetView v-else :health-target="target" v-for="target in healthCheckStore.targets"/>
</VCardText>
</VCard>
</VContainer>
<HealthTargetView v-else :health-target="target" v-for="target in healthCheckStore.targets"/>
</VCardText>
</VCard>
</VContainer>
</div>
</template>

<style scoped>
Expand Down
83 changes: 83 additions & 0 deletions client/src/views/HealthCheck/HealthDay.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {HealthDay, HealthTarget, useHealthCheckStore} from "../../stores/healthcheck.store.ts";
import {equalDate} from "../Utils.ts";

export class HealthDayService {
private healthDay: HealthDay | undefined

constructor(healthDay: HealthDay | undefined) {
this.healthDay = healthDay
}

static fromDay(healthTarget: HealthTarget, d: number) {
const healthCheckStore = useHealthCheckStore()
const date = this.showDate(d)
const healthDay = healthCheckStore.getDays(healthTarget)?.find(el => {
const day = new Date(el.date)
return equalDate(date, day)
})
return new HealthDayService(healthDay)
}

static showDate(d: number) {
const date = new Date();
date.setDate(date.getDate() - d + 1);
return date
}

getStatus() {
const fallTimes = this.getFallTimes()
if (fallTimes == undefined) return 'Lost'
if (fallTimes > 0) {
return 'Downtime'
}
return `Operational`
}

getDescription() {
const fallTimes = this.getFallTimes()
const lostTimes = this.getLostTimes()
let res = ''
if (fallTimes != undefined && fallTimes > 0) {
res += `Down for ${fallTimes} minutes`
}
if (lostTimes != undefined && lostTimes > 0) {
res += `<br>Lost for ${lostTimes} minutes`
}
return res;
}

getPercentage() {
if (this.healthDay == undefined) return
const fallTimes = this.getFallTimes()
const lostTimes = this.getLostTimes()
if (!fallTimes) return undefined
return (fallTimes / this.healthDay.count_response_time) * 100 + (lostTimes / (60 * 24)) * 30
}

getFallTimes() {
if (!this.healthDay) return
return this.healthDay.fall_times
}

getLostTimes() {
const maxTimes = this.getMaxTimes()
const responseTime = this.healthDay?.count_response_time
if (responseTime == undefined) return 0
const lostTimes = maxTimes - responseTime
return lostTimes > 30 ? lostTimes : 0
}

getMaxTimes() {
let maxTimes = 60 * 24
if (this.isToday()) {
const now = new Date()
return now.getHours() * 24 + now.getMinutes()
}
return maxTimes
}

isToday() {
if (!this.healthDay) return
return equalDate(new Date(), new Date(this.healthDay.date))
}
}
126 changes: 77 additions & 49 deletions client/src/views/HealthCheck/HealthTargetView.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<script lang="ts">
import {defineComponent, PropType} from 'vue'
import {HealthDay, HealthTarget, useHealthCheckStore} from "../../stores/healthcheck.store.ts";
import {HealthTarget, useHealthCheckStore} from "../../stores/healthcheck.store.ts";
import {FontAwesomeIcon} from "@fortawesome/vue-fontawesome";
import StatusRect from "../Project/Status/StatusRect.vue";
import {HealthDayService} from "./HealthDay.service.ts";
import {Line} from 'vue-chartjs'
import moment from "moment";
export default defineComponent({
name: "HealthTargetView",
components: {StatusRect, FontAwesomeIcon},
components: {StatusRect, FontAwesomeIcon, Line},
props: {
healthTarget: {
type: Object as PropType<HealthTarget>,
Expand All @@ -19,6 +22,44 @@ export default defineComponent({
healthCheckStore
}
},
computed: {
options() {
return {
plugins: {
tooltip: {
mode: 'index',
intersect: false
},
legend: {
display: false // это отключает отображение легенды на графике
},
},
elements: {
point: {
radius: 0.1
}
},
scales: {
y: {
ticks: {
// Include a dollar sign in the ticks
callback: function(value, index, ticks) {
return value + ' s';
}
},
},
x: {
type: 'time',
grid: {
display: false
}
}
},
responsive: true,
maintainAspectRatio: false,
}
}
},
methods: {
getTargetStatus() {
const lastUnit = this.healthCheckStore.getLastUnit(this.healthTarget)
Expand All @@ -27,52 +68,33 @@ export default defineComponent({
if (timeSpent > 180)
return;
return lastUnit.status;
},
getStatus(d: number) {
const day = this.getDay(d)
if (day == undefined) return 'Undefined'
const fallTimes = this.getFallTimes(day)
if (fallTimes > 0) {
return 'Downtime'
}
return `Operational`
return lastUnit.status
},
getDescription(d: number) {
const day = this.getDay(d)
if (day == undefined) return undefined
const fallTimes = this.getFallTimes(day)
if (fallTimes > 0) {
return `Down for ${fallTimes} minutes`
getChartData() {
const units = this.healthCheckStore.getUnits(this.healthTarget)?.reverse()
if (units == undefined) return
return {
labels: units?.map(el => moment(el.request_datetime)),
datasets: [{
label: 'Response Time',
data: units?.map(el => el.response_time),
borderWidth: 1,
borderColor: 'rgb(0,83,255)',
}]
}
},
getPercentage(d: number) {
const day = this.getDay(d)
if (day == undefined) return undefined
const fallTimes = this.getFallTimes(day)
return (fallTimes / (60 * 24)) * 200
},
getFallTimes(day: HealthDay) {
let maxTimes = 60 * 24
if (day.id == this.getDay(1)?.id) {
const now = new Date()
maxTimes = now.getHours() * 24 + now.getMinutes()
buildDayStatuses() {
const result = []
for (let i = 1; i < 90; i++) {
const healthDayService = HealthDayService.fromDay(this.healthTarget, i);
result.push({
percentage: healthDayService.getPercentage(),
date: HealthDayService.showDate(i),
status: healthDayService.getStatus(),
description: healthDayService.getDescription(),
})
}
const lostTimes = maxTimes - day.count_response_time
return day.fall_times + lostTimes > 5 ? lostTimes : 0
},
showDate(d: number) {
const date = new Date();
date.setDate(date.getDate() - d + 1);
return date
},
getDay(d: number) {
const date = this.showDate(d)
return this.healthCheckStore.getDays(this.healthTarget)?.find(el => {
const day = new Date(el.date)
return day.getDate() == date.getDate() && day.getMonth() == date.getMonth() && day.getFullYear() == date.getFullYear()
})
return result
}
}
})
Expand All @@ -98,13 +120,19 @@ export default defineComponent({
<VCardText>
<div class="chart">
<StatusRect
:percentage="getPercentage(d)"
:date="showDate(d)"
:status="getStatus(d)"
:description="getDescription(d)"
v-for="d in 90"
:percentage="d.percentage"
:date="d.date"
:status="d.status"
:description="d.description"
v-for="d in buildDayStatuses()"
/>
</div>
<p class="ma-1">
Response Times:
</p>
<div style="height: 10rem" v-if="getChartData()">
<Line :data="getChartData()" :options="options"/>
</div>
</VCardText>
</VCard>
</template>
Expand Down
3 changes: 1 addition & 2 deletions client/src/views/Project/Status/StatusRect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,7 @@ export default defineComponent({
<div v-if="status">
{{ status }}
</div>
<div v-if="description">
{{ description }}
<div v-if="description" v-html="description">
</div>
<div>
{{ dateFormat(date) }}
Expand Down
3 changes: 3 additions & 0 deletions client/src/views/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,6 @@ export function chunk<T>(arr: T[], size: number): T[][] {
);
}

export function equalDate(a: Date, b: Date) {
return a.getDate() == b.getDate() && a.getMonth() == b.getMonth() && a.getFullYear() == b.getFullYear()
}
Loading

0 comments on commit ebd4596

Please sign in to comment.