mirror of
https://github.com/vitodeploy/vito.git
synced 2025-04-19 18:01:37 +00:00
add data retention to the metrics
This commit is contained in:
parent
ddacc32e64
commit
52d195710b
@ -46,13 +46,13 @@ private function metrics(
|
|||||||
->select(
|
->select(
|
||||||
[
|
[
|
||||||
DB::raw('created_at as date'),
|
DB::raw('created_at as date'),
|
||||||
DB::raw('AVG(load) as load'),
|
DB::raw('ROUND(AVG(load), 2) as load'),
|
||||||
DB::raw('AVG(memory_total) as memory_total'),
|
DB::raw('ROUND(AVG(memory_total), 2) as memory_total'),
|
||||||
DB::raw('AVG(memory_used) as memory_used'),
|
DB::raw('ROUND(AVG(memory_used), 2) as memory_used'),
|
||||||
DB::raw('AVG(memory_free) as memory_free'),
|
DB::raw('ROUND(AVG(memory_free), 2) as memory_free'),
|
||||||
DB::raw('AVG(disk_total) as disk_total'),
|
DB::raw('ROUND(AVG(disk_total), 2) as disk_total'),
|
||||||
DB::raw('AVG(disk_used) as disk_used'),
|
DB::raw('ROUND(AVG(disk_used), 2) as disk_used'),
|
||||||
DB::raw('AVG(disk_free) as disk_free'),
|
DB::raw('ROUND(AVG(disk_free), 2) as disk_free'),
|
||||||
$interval,
|
$interval,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
32
app/Actions/Monitoring/UpdateMetricSettings.php
Normal file
32
app/Actions/Monitoring/UpdateMetricSettings.php
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Monitoring;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Support\Facades\Validator;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
|
class UpdateMetricSettings
|
||||||
|
{
|
||||||
|
public function update(Server $server, array $input): void
|
||||||
|
{
|
||||||
|
$this->validate($input);
|
||||||
|
|
||||||
|
$service = $server->monitoring();
|
||||||
|
|
||||||
|
$data = $service->handler()->data();
|
||||||
|
$data['data_retention'] = $input['data_retention'];
|
||||||
|
$service->type_data = $data;
|
||||||
|
$service->save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function validate(array $input): void
|
||||||
|
{
|
||||||
|
Validator::make($input, [
|
||||||
|
'data_retention' => [
|
||||||
|
'required',
|
||||||
|
Rule::in(config('core.metrics_data_retention')),
|
||||||
|
],
|
||||||
|
])->validate();
|
||||||
|
}
|
||||||
|
}
|
28
app/Console/Commands/DeleteOlderMetricsCommand.php
Normal file
28
app/Console/Commands/DeleteOlderMetricsCommand.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Service;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class DeleteOlderMetricsCommand extends Command
|
||||||
|
{
|
||||||
|
protected $signature = 'metrics:delete-older-metrics';
|
||||||
|
|
||||||
|
protected $description = 'Delete older metrics from database';
|
||||||
|
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
Service::query()->where('type', 'monitoring')->chunk(100, function ($services) {
|
||||||
|
$services->each(function ($service) {
|
||||||
|
$this->info("Deleting older metrics for service {$service->server->name}");
|
||||||
|
$service
|
||||||
|
->server
|
||||||
|
->metrics()
|
||||||
|
->where('created_at', '<', now()->subDays($service->handler()->data()['data_retention']))
|
||||||
|
->delete();
|
||||||
|
$this->info('Metrics deleted');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,7 @@ protected function schedule(Schedule $schedule): void
|
|||||||
$schedule->command('backups:run "0 0 * * *"')->daily();
|
$schedule->command('backups:run "0 0 * * *"')->daily();
|
||||||
$schedule->command('backups:run "0 0 * * 0"')->weekly();
|
$schedule->command('backups:run "0 0 * * 0"')->weekly();
|
||||||
$schedule->command('backups:run "0 0 1 * *"')->monthly();
|
$schedule->command('backups:run "0 0 1 * *"')->monthly();
|
||||||
|
$schedule->command('metrics:delete-older-metrics')->daily();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Actions\Monitoring\GetMetrics;
|
use App\Actions\Monitoring\GetMetrics;
|
||||||
|
use App\Actions\Monitoring\UpdateMetricSettings;
|
||||||
use App\Facades\Toast;
|
use App\Facades\Toast;
|
||||||
|
use App\Helpers\HtmxResponse;
|
||||||
use App\Models\Server;
|
use App\Models\Server;
|
||||||
use Illuminate\Contracts\View\View;
|
use Illuminate\Contracts\View\View;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
@ -13,15 +15,30 @@ class MetricController extends Controller
|
|||||||
{
|
{
|
||||||
public function index(Server $server, Request $request): View|RedirectResponse
|
public function index(Server $server, Request $request): View|RedirectResponse
|
||||||
{
|
{
|
||||||
if (! $server->service('monitoring')) {
|
$this->checkIfMonitoringServiceInstalled($server);
|
||||||
Toast::error('You need to install monitoring service first');
|
|
||||||
|
|
||||||
return redirect()->route('servers.services', $server);
|
|
||||||
}
|
|
||||||
|
|
||||||
return view('metrics.index', [
|
return view('metrics.index', [
|
||||||
'server' => $server,
|
'server' => $server,
|
||||||
'data' => app(GetMetrics::class)->filter($server, $request->input()),
|
'data' => app(GetMetrics::class)->filter($server, $request->input()),
|
||||||
|
'lastMetric' => $server->metrics()->latest()->first(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function settings(Server $server, Request $request): HtmxResponse
|
||||||
|
{
|
||||||
|
$this->checkIfMonitoringServiceInstalled($server);
|
||||||
|
|
||||||
|
app(UpdateMetricSettings::class)->update($server, $request->input());
|
||||||
|
|
||||||
|
Toast::success('Metric settings updated successfully');
|
||||||
|
|
||||||
|
return htmx()->back();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function checkIfMonitoringServiceInstalled(Server $server): void
|
||||||
|
{
|
||||||
|
if (! $server->monitoring()) {
|
||||||
|
abort(404, 'Monitoring service is not installed on this server');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,7 @@ public function creationData(array $input): array
|
|||||||
return [
|
return [
|
||||||
'url' => '',
|
'url' => '',
|
||||||
'secret' => Uuid::uuid4()->toString(),
|
'secret' => Uuid::uuid4()->toString(),
|
||||||
|
'data_retention' => 10,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,6 +44,7 @@ public function data(): array
|
|||||||
return [
|
return [
|
||||||
'url' => $this->service->type_data['url'] ?? null,
|
'url' => $this->service->type_data['url'] ?? null,
|
||||||
'secret' => $this->service->type_data['secret'] ?? null,
|
'secret' => $this->service->type_data['secret'] ?? null,
|
||||||
|
'data_retention' => $this->service->type_data['data_retention'] ?? 10,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,4 +367,11 @@
|
|||||||
\App\Enums\SslType::LETSENCRYPT,
|
\App\Enums\SslType::LETSENCRYPT,
|
||||||
\App\Enums\SslType::CUSTOM,
|
\App\Enums\SslType::CUSTOM,
|
||||||
],
|
],
|
||||||
|
|
||||||
|
'metrics_data_retention' => [
|
||||||
|
7,
|
||||||
|
14,
|
||||||
|
30,
|
||||||
|
90,
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
1
public/build/assets/app-53e4d707.css
Normal file
1
public/build/assets/app-53e4d707.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"resources/css/app.css": {
|
"resources/css/app.css": {
|
||||||
"file": "assets/app-bc2bbb2b.css",
|
"file": "assets/app-53e4d707.css",
|
||||||
"isEntry": true,
|
"isEntry": true,
|
||||||
"src": "resources/css/app.css"
|
"src": "resources/css/app.css"
|
||||||
},
|
},
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
"sets",
|
"sets",
|
||||||
"categories",
|
"categories",
|
||||||
"toolbar" => false,
|
"toolbar" => false,
|
||||||
|
"formatter" => null,
|
||||||
])
|
])
|
||||||
<x-simple-card {{ $attributes }}>
|
<x-simple-card {{ $attributes }}>
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
@ -87,9 +88,9 @@
|
|||||||
yaxis: {
|
yaxis: {
|
||||||
show: false,
|
show: false,
|
||||||
labels: {
|
labels: {
|
||||||
formatter: function (value) {
|
@if ($formatter)
|
||||||
return parseInt(value);
|
formatter: {{ $formatter }},
|
||||||
}
|
@endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,68 +1,106 @@
|
|||||||
<x-server-layout :server="$server">
|
<x-server-layout :server="$server">
|
||||||
<x-slot name="pageTitle">{{ $server->name }} - Metrics</x-slot>
|
<x-slot name="pageTitle">{{ $server->name }} - Metrics</x-slot>
|
||||||
|
|
||||||
@include("metrics.partials.filter")
|
<div class="space-y-4">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
@include("metrics.partials.filter")
|
||||||
|
@include("metrics.partials.data-retention")
|
||||||
|
</div>
|
||||||
|
@php
|
||||||
|
$cpuSets = [
|
||||||
|
"name" => "CPU Load",
|
||||||
|
"data" => $data["metrics"]->pluck("load")->toArray(),
|
||||||
|
"color" => "#ff9900",
|
||||||
|
];
|
||||||
|
$memorySets = [
|
||||||
|
"name" => "Memory Usage",
|
||||||
|
"data" => $data["metrics"]->pluck("memory_used")->toArray(),
|
||||||
|
"color" => "#3366cc",
|
||||||
|
];
|
||||||
|
$diskSets = [
|
||||||
|
"name" => "Disk Usage",
|
||||||
|
"data" => $data["metrics"]->pluck("disk_used")->toArray(),
|
||||||
|
"color" => "#109618",
|
||||||
|
];
|
||||||
|
@endphp
|
||||||
|
|
||||||
@php
|
<div class="grid grid-cols-1 gap-4 lg:grid-cols-3">
|
||||||
$cpuSets = [
|
<x-chart
|
||||||
"name" => "CPU Load",
|
id="cpu-load"
|
||||||
"data" => $data["metrics"]->pluck("load")->toArray(),
|
type="area"
|
||||||
"color" => "#ff9900",
|
title="CPU Load"
|
||||||
];
|
:sets="[$cpuSets]"
|
||||||
$memorySets = [
|
:categories="$data['metrics']->pluck('date')->toArray()"
|
||||||
"name" => "Memory Usage",
|
color="#ff9900"
|
||||||
"data" => $data["metrics"]->pluck("memory_used")->toArray(),
|
class="h-[200px] !p-0"
|
||||||
"color" => "#3366cc",
|
/>
|
||||||
];
|
|
||||||
$diskSets = [
|
|
||||||
"name" => "Disk Usage",
|
|
||||||
"data" => $data["metrics"]->pluck("disk_used")->toArray(),
|
|
||||||
"color" => "#109618",
|
|
||||||
];
|
|
||||||
@endphp
|
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-4 lg:grid-cols-3">
|
<x-chart
|
||||||
<x-chart
|
id="memory-usage"
|
||||||
id="cpu-load"
|
type="area"
|
||||||
type="area"
|
title="Memory"
|
||||||
title="CPU Load"
|
:sets="[$memorySets]"
|
||||||
:sets="[$cpuSets]"
|
:categories="$data['metrics']->pluck('date')->toArray()"
|
||||||
:categories="$data['metrics']->pluck('date')->toArray()"
|
color="#3366cc"
|
||||||
color="#ff9900"
|
formatter="function (value) { return (value / 1000).toFixed(2) + ` MB`; }"
|
||||||
class="h-[200px] !p-0"
|
class="h-[200px] !p-0"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<x-chart
|
<x-chart
|
||||||
id="memory-usage"
|
id="disk-usage"
|
||||||
type="area"
|
type="area"
|
||||||
title="Memory"
|
title="Disk"
|
||||||
:sets="[$memorySets]"
|
:sets="[$diskSets]"
|
||||||
:categories="$data['metrics']->pluck('date')->toArray()"
|
:categories="$data['metrics']->pluck('date')->toArray()"
|
||||||
color="#3366cc"
|
formatter="function (value) { return value + ` MB`; }"
|
||||||
class="h-[200px] !p-0"
|
color="#109618"
|
||||||
/>
|
class="h-[200px] !p-0"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<x-chart
|
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
id="disk-usage"
|
<div class="grid grid-cols-1 gap-4">
|
||||||
type="area"
|
<x-simple-card class="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
||||||
title="Disk"
|
<span class="text-center lg:text-left">Total Memory</span>
|
||||||
:sets="[$diskSets]"
|
<div class="text-center text-xl font-bold text-gray-600 dark:text-gray-400 lg:text-right">
|
||||||
:categories="$data['metrics']->pluck('date')->toArray()"
|
{{ $lastMetric->memory_total }} MB
|
||||||
color="#109618"
|
</div>
|
||||||
class="h-[200px] !p-0"
|
</x-simple-card>
|
||||||
/>
|
<x-simple-card class="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
||||||
|
<span class="text-center lg:text-left">Used Memory</span>
|
||||||
|
<div class="text-center text-xl font-bold text-gray-600 dark:text-gray-400 lg:text-right">
|
||||||
|
{{ $lastMetric->memory_used }} MB
|
||||||
|
</div>
|
||||||
|
</x-simple-card>
|
||||||
|
<x-simple-card class="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
||||||
|
<span class="text-center lg:text-left">Free Memory</span>
|
||||||
|
<div class="text-center text-xl font-bold text-gray-600 dark:text-gray-400 lg:text-right">
|
||||||
|
{{ $lastMetric->memory_free }} MB
|
||||||
|
</div>
|
||||||
|
</x-simple-card>
|
||||||
|
</div>
|
||||||
|
<div class="grid grid-cols-1 gap-4">
|
||||||
|
<x-simple-card class="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
||||||
|
<span class="text-center lg:text-left">Total Space</span>
|
||||||
|
<div class="text-center text-xl font-bold text-gray-600 dark:text-gray-400 lg:text-right">
|
||||||
|
{{ $lastMetric->disk_total }} MB
|
||||||
|
</div>
|
||||||
|
</x-simple-card>
|
||||||
|
<x-simple-card class="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
||||||
|
<span class="text-center lg:text-left">Used Space</span>
|
||||||
|
<div class="text-center text-xl font-bold text-gray-600 dark:text-gray-400 lg:text-right">
|
||||||
|
{{ $lastMetric->disk_used }} MB
|
||||||
|
</div>
|
||||||
|
</x-simple-card>
|
||||||
|
<x-simple-card class="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
||||||
|
<span class="text-center lg:text-left">Free Space</span>
|
||||||
|
<div class="text-center text-xl font-bold text-gray-600 dark:text-gray-400 lg:text-right">
|
||||||
|
{{ $lastMetric->disk_free }} MB
|
||||||
|
</div>
|
||||||
|
</x-simple-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-10">
|
@stack("modals")
|
||||||
<x-chart
|
|
||||||
id="resource-usage"
|
|
||||||
type="line"
|
|
||||||
title="Resource Usage"
|
|
||||||
:sets="[$cpuSets, $memorySets, $diskSets]"
|
|
||||||
:categories="$data['metrics']->pluck('date')->toArray()"
|
|
||||||
color="#109618"
|
|
||||||
:toolbar="true"
|
|
||||||
class="h-[400px] !px-0 !pt-0"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</x-server-layout>
|
</x-server-layout>
|
||||||
|
44
resources/views/metrics/partials/data-retention.blade.php
Normal file
44
resources/views/metrics/partials/data-retention.blade.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<x-secondary-button
|
||||||
|
class="ml-2 hidden h-[42px] items-center lg:flex"
|
||||||
|
x-on:click="$dispatch('open-modal', 'metric-settings')"
|
||||||
|
>
|
||||||
|
<x-heroicon name="o-trash" class="mr-1 h-5 w-5" />
|
||||||
|
Data Retention
|
||||||
|
</x-secondary-button>
|
||||||
|
@push("modals")
|
||||||
|
<x-modal name="metric-settings">
|
||||||
|
<form
|
||||||
|
id="metric-settings-form"
|
||||||
|
hx-post="{{ route("servers.metrics.settings", ["server" => $server]) }}"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
hx-select="#metric-settings-form"
|
||||||
|
class="p-6"
|
||||||
|
>
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<h2 class="text-lg font-medium text-gray-900 dark:text-gray-100">Data Retention</h2>
|
||||||
|
|
||||||
|
<div class="mt-6">
|
||||||
|
<x-input-label for="data_retention" value="Delete metrics older than" />
|
||||||
|
<x-select-input id="data_retention" name="data_retention" class="mt-1 w-full">
|
||||||
|
@foreach (config("core.metrics_data_retention") as $item)
|
||||||
|
<option value="{{ $item }}">{{ $item }} Days</option>
|
||||||
|
@endforeach
|
||||||
|
</x-select-input>
|
||||||
|
@error("data_retention")
|
||||||
|
<x-input-error class="mt-2" :messages="$message" />
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-6 flex justify-end">
|
||||||
|
<x-secondary-button type="button" x-on:click="$dispatch('close')">
|
||||||
|
{{ __("Cancel") }}
|
||||||
|
</x-secondary-button>
|
||||||
|
|
||||||
|
<x-primary-button id="btn-metric-settings" hx-disable class="ml-3">
|
||||||
|
{{ __("Save") }}
|
||||||
|
</x-primary-button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</x-modal>
|
||||||
|
@endpush
|
@ -13,20 +13,7 @@ class="@if($server->webserver() && $server->database()) grid-cols-3 @else grid-c
|
|||||||
@if ($server->webserver())
|
@if ($server->webserver())
|
||||||
<div class="border-r border-gray-200 p-5 dark:border-gray-900">
|
<div class="border-r border-gray-200 p-5 dark:border-gray-900">
|
||||||
<div class="flex items-center justify-center md:justify-start">
|
<div class="flex items-center justify-center md:justify-start">
|
||||||
<svg
|
<x-heroicon name="o-globe-alt" class="h-8 w-8 text-primary-500" />
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke-width="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
class="h-8 w-8 text-primary-500"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
d="M12 21a9.004 9.004 0 008.716-6.747M12 21a9.004 9.004 0 01-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 017.843 4.582M12 3a8.997 8.997 0 00-7.843 4.582m15.686 0A11.953 11.953 0 0112 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0121 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0112 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 013 12c0-1.605.42-3.113 1.157-4.418"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<div class="ml-2 hidden md:block">{{ __("Sites") }}</div>
|
<div class="ml-2 hidden md:block">{{ __("Sites") }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 text-center text-3xl font-bold text-gray-600 dark:text-gray-400 md:text-left">
|
<div class="mt-3 text-center text-3xl font-bold text-gray-600 dark:text-gray-400 md:text-left">
|
||||||
@ -38,20 +25,7 @@ class="h-8 w-8 text-primary-500"
|
|||||||
@if ($server->database())
|
@if ($server->database())
|
||||||
<div class="border-r border-gray-200 p-5 dark:border-gray-900">
|
<div class="border-r border-gray-200 p-5 dark:border-gray-900">
|
||||||
<div class="flex items-center justify-center md:justify-start">
|
<div class="flex items-center justify-center md:justify-start">
|
||||||
<svg
|
<x-heroicon name="o-circle-stack" class="h-8 w-8 text-primary-500" />
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke-width="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
class="h-8 w-8 text-primary-500"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
d="M20.25 6.375c0 2.278-3.694 4.125-8.25 4.125S3.75 8.653 3.75 6.375m16.5 0c0-2.278-3.694-4.125-8.25-4.125S3.75 4.097 3.75 6.375m16.5 0v11.25c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125V6.375m16.5 0v3.75m-16.5-3.75v3.75m16.5 0v3.75C20.25 16.153 16.556 18 12 18s-8.25-1.847-8.25-4.125v-3.75m16.5 0c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<div class="ml-2 hidden md:block">
|
<div class="ml-2 hidden md:block">
|
||||||
{{ __("Databases") }}
|
{{ __("Databases") }}
|
||||||
</div>
|
</div>
|
||||||
@ -64,20 +38,7 @@ class="h-8 w-8 text-primary-500"
|
|||||||
|
|
||||||
<div class="p-5">
|
<div class="p-5">
|
||||||
<div class="flex items-center justify-center md:justify-start">
|
<div class="flex items-center justify-center md:justify-start">
|
||||||
<svg
|
<x-heroicon name="o-clock" class="h-8 w-8 text-primary-500" />
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
stroke-width="1.5"
|
|
||||||
stroke="currentColor"
|
|
||||||
class="h-8 w-8 text-primary-500"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
stroke-linecap="round"
|
|
||||||
stroke-linejoin="round"
|
|
||||||
d="M12 6v6h4.5m4.5 0a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
<div class="ml-2 hidden md:block">{{ __("Cron Jobs") }}</div>
|
<div class="ml-2 hidden md:block">{{ __("Cron Jobs") }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-3 text-center text-3xl font-bold text-gray-600 dark:text-gray-400 md:text-left">
|
<div class="mt-3 text-center text-3xl font-bold text-gray-600 dark:text-gray-400 md:text-left">
|
||||||
|
@ -5,29 +5,31 @@
|
|||||||
<x-slot name="aside"></x-slot>
|
<x-slot name="aside"></x-slot>
|
||||||
</x-card-header>
|
</x-card-header>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 gap-5 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
<x-live id="live-available-services">
|
||||||
@foreach (config("core.service_handlers") as $key => $addOn)
|
<div class="grid grid-cols-1 gap-5 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
||||||
@if (! $server->services()->where("name", $key)->exists())
|
@foreach (config("core.service_handlers") as $key => $addOn)
|
||||||
<div
|
@if (! $server->services()->where("name", $key)->exists())
|
||||||
class="relative flex h-auto flex-col items-center justify-between space-y-3 rounded-b-md rounded-t-md border border-gray-200 bg-white text-center dark:border-gray-700 dark:bg-gray-800"
|
<div
|
||||||
>
|
class="relative flex h-auto flex-col items-center justify-between space-y-3 rounded-b-md rounded-t-md border border-gray-200 bg-white text-center dark:border-gray-700 dark:bg-gray-800"
|
||||||
<div class="space-y-3 p-5">
|
>
|
||||||
<div class="flex items-center justify-center">
|
<div class="space-y-3 p-5">
|
||||||
<img src="{{ asset("static/images/" . $key . ".svg") }}" class="h-20 w-20" alt="" />
|
<div class="flex items-center justify-center">
|
||||||
</div>
|
<img src="{{ asset("static/images/" . $key . ".svg") }}" class="h-20 w-20" alt="" />
|
||||||
<div class="flex flex-grow flex-col items-center justify-center">
|
</div>
|
||||||
<div class="flex items-center justify-center text-center text-lg">
|
<div class="flex flex-grow flex-col items-center justify-center">
|
||||||
{{ $key }}
|
<div class="flex items-center justify-center text-center text-lg">
|
||||||
|
{{ $key }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex w-full items-center justify-between rounded-b-md border-t border-t-gray-200 bg-gray-50 p-2 dark:border-t-gray-600 dark:bg-gray-700"
|
||||||
|
>
|
||||||
|
@include("services.partials.installers." . $key)
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
@endif
|
||||||
class="flex w-full items-center justify-between rounded-b-md border-t border-t-gray-200 bg-gray-50 p-2 dark:border-t-gray-600 dark:bg-gray-700"
|
@endforeach
|
||||||
>
|
</div>
|
||||||
@include("services.partials.installers." . $key)
|
</x-live>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
@endforeach
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -132,6 +132,7 @@
|
|||||||
|
|
||||||
// metrics
|
// metrics
|
||||||
Route::get('/{server}/metrics', [MetricController::class, 'index'])->name('servers.metrics');
|
Route::get('/{server}/metrics', [MetricController::class, 'index'])->name('servers.metrics');
|
||||||
|
Route::post('/{server}/metrics/settings', [MetricController::class, 'settings'])->name('servers.metrics.settings');
|
||||||
|
|
||||||
// console
|
// console
|
||||||
Route::get('/{server}/console', [ConsoleController::class, 'index'])->name('servers.console');
|
Route::get('/{server}/console', [ConsoleController::class, 'index'])->name('servers.console');
|
||||||
|
@ -35,6 +35,29 @@ public function test_cannot_visit_metrics(): void
|
|||||||
$this->actingAs($this->user);
|
$this->actingAs($this->user);
|
||||||
|
|
||||||
$this->get(route('servers.metrics', ['server' => $this->server]))
|
$this->get(route('servers.metrics', ['server' => $this->server]))
|
||||||
->assertRedirect(route('servers.services', ['server' => $this->server]));
|
->assertNotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_update_data_retention(): void
|
||||||
|
{
|
||||||
|
$this->actingAs($this->user);
|
||||||
|
|
||||||
|
Service::factory()->create([
|
||||||
|
'server_id' => $this->server->id,
|
||||||
|
'name' => 'vito-agent',
|
||||||
|
'type' => 'monitoring',
|
||||||
|
'version' => 'latest',
|
||||||
|
'status' => ServiceStatus::READY,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->post(route('servers.metrics.settings', ['server' => $this->server]), [
|
||||||
|
'data_retention' => 30,
|
||||||
|
])->assertSessionHas('toast.type', 'success');
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('services', [
|
||||||
|
'server_id' => $this->server->id,
|
||||||
|
'type' => 'monitoring',
|
||||||
|
'type_data->data_retention' => 30,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
49
tests/Unit/Commands/DeleteOlderMetricsCommandTest.php
Normal file
49
tests/Unit/Commands/DeleteOlderMetricsCommandTest.php
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Unit\Commands;
|
||||||
|
|
||||||
|
use App\Enums\ServiceStatus;
|
||||||
|
use App\Models\Metric;
|
||||||
|
use App\Models\Service;
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Carbon\CarbonPeriod;
|
||||||
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||||
|
use Tests\TestCase;
|
||||||
|
|
||||||
|
class DeleteOlderMetricsCommandTest extends TestCase
|
||||||
|
{
|
||||||
|
use RefreshDatabase;
|
||||||
|
|
||||||
|
public function test_delete_older_metrics(): void
|
||||||
|
{
|
||||||
|
$monitoring = Service::factory()->create([
|
||||||
|
'server_id' => $this->server->id,
|
||||||
|
'name' => 'vito-agent',
|
||||||
|
'type' => 'monitoring',
|
||||||
|
'type_data' => [
|
||||||
|
'data_retention' => 1,
|
||||||
|
],
|
||||||
|
'version' => 'latest',
|
||||||
|
'status' => ServiceStatus::READY,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$range = CarbonPeriod::create(Carbon::now()->subDays(10), '1 hour', Carbon::now()->subDays(8));
|
||||||
|
foreach ($range as $date) {
|
||||||
|
Metric::factory()->create([
|
||||||
|
'server_id' => $monitoring->server_id,
|
||||||
|
'created_at' => $date,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertDatabaseHas('metrics', [
|
||||||
|
'server_id' => $this->server->id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->artisan('metrics:delete-older-metrics')
|
||||||
|
->expectsOutput('Metrics deleted');
|
||||||
|
|
||||||
|
$this->assertDatabaseMissing('metrics', [
|
||||||
|
'server_id' => $this->server->id,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user