feat: container logs
This commit is contained in:
parent
fd9c13009f
commit
97027875bf
40
app/Http/Livewire/Project/Shared/GetLogs.php
Normal file
40
app/Http/Livewire/Project/Shared/GetLogs.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Project\Shared;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Support\Facades\Process;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class GetLogs extends Component
|
||||||
|
{
|
||||||
|
public string $outputs = '';
|
||||||
|
public string $errors = '';
|
||||||
|
public Server $server;
|
||||||
|
public ?string $container = null;
|
||||||
|
public ?bool $streamLogs = false;
|
||||||
|
|
||||||
|
public function doSomethingWithThisChunkOfOutput($output)
|
||||||
|
{
|
||||||
|
$this->outputs .= $output;
|
||||||
|
}
|
||||||
|
public function instantSave()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public function getLogs($refresh = false)
|
||||||
|
{
|
||||||
|
if ($this->container) {
|
||||||
|
$sshCommand = generateSshCommand($this->server, "docker logs -t {$this->container}");
|
||||||
|
if ($refresh) {
|
||||||
|
$this->outputs = '';
|
||||||
|
}
|
||||||
|
Process::run($sshCommand, function (string $type, string $output) {
|
||||||
|
$this->doSomethingWithThisChunkOfOutput($output);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.project.shared.get-logs');
|
||||||
|
}
|
||||||
|
}
|
53
app/Http/Livewire/Project/Shared/Logs.php
Normal file
53
app/Http/Livewire/Project/Shared/Logs.php
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Project\Shared;
|
||||||
|
|
||||||
|
use App\Models\Application;
|
||||||
|
use App\Models\Server;
|
||||||
|
use App\Models\Service;
|
||||||
|
use App\Models\StandalonePostgresql;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class Logs extends Component
|
||||||
|
{
|
||||||
|
public ?string $type = null;
|
||||||
|
public Application|StandalonePostgresql|Service $resource;
|
||||||
|
public Server $server;
|
||||||
|
public ?string $container = null;
|
||||||
|
public $parameters;
|
||||||
|
public $query;
|
||||||
|
public $status;
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
|
$this->query = request()->query();
|
||||||
|
if (data_get($this->parameters, 'application_uuid')) {
|
||||||
|
$this->type = 'application';
|
||||||
|
$this->resource = Application::where('uuid', $this->parameters['application_uuid'])->firstOrFail();
|
||||||
|
$this->status = $this->resource->status;
|
||||||
|
$this->server = $this->resource->destination->server;
|
||||||
|
$containers = getCurrentApplicationContainerStatus($this->server, $this->resource->id);
|
||||||
|
if ($containers->count() > 0) {
|
||||||
|
$this->container = data_get($containers[0], 'Names');
|
||||||
|
}
|
||||||
|
} else if (data_get($this->parameters, 'database_uuid')) {
|
||||||
|
$this->type = 'database';
|
||||||
|
$this->resource = StandalonePostgresql::where('uuid', $this->parameters['database_uuid'])->firstOrFail();
|
||||||
|
$this->status = $this->resource->status;
|
||||||
|
$this->server = $this->resource->destination->server;
|
||||||
|
$this->container = $this->resource->uuid;
|
||||||
|
} else if (data_get($this->parameters, 'service_uuid')) {
|
||||||
|
$this->type = 'service';
|
||||||
|
$this->resource = Service::where('uuid', $this->parameters['service_uuid'])->firstOrFail();
|
||||||
|
$this->status = $this->resource->status;
|
||||||
|
$this->server = $this->resource->server;
|
||||||
|
$this->container = data_get($this->parameters, 'service_name') . '-' . $this->resource->uuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.project.shared.logs');
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,10 @@
|
|||||||
href="{{ route('project.application.deployments', $parameters) }}">
|
href="{{ route('project.application.deployments', $parameters) }}">
|
||||||
<button>Deployments</button>
|
<button>Deployments</button>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="{{ request()->routeIs('project.application.logs') ? 'text-white' : '' }}"
|
||||||
|
href="{{ route('project.application.logs', $parameters) }}">
|
||||||
|
<button>Logs</button>
|
||||||
|
</a>
|
||||||
<x-applications.links :application="$application" />
|
<x-applications.links :application="$application" />
|
||||||
<div class="flex-1"></div>
|
<div class="flex-1"></div>
|
||||||
<x-applications.advanced :application="$application" />
|
<x-applications.advanced :application="$application" />
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
href="{{ route('project.database.configuration', $parameters) }}">
|
href="{{ route('project.database.configuration', $parameters) }}">
|
||||||
<button>Configuration</button>
|
<button>Configuration</button>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="{{ request()->routeIs('project.database.logs') ? 'text-white' : '' }}"
|
||||||
|
href="{{ route('project.database.logs', $parameters) }}">
|
||||||
|
<button>Logs</button>
|
||||||
|
</a>
|
||||||
<a class="{{ request()->routeIs('project.database.backups.all') ? 'text-white' : '' }}"
|
<a class="{{ request()->routeIs('project.database.backups.all') ? 'text-white' : '' }}"
|
||||||
href="{{ route('project.database.backups.all', $parameters) }}">
|
href="{{ route('project.database.backups.all', $parameters) }}">
|
||||||
<button>Backups</button>
|
<button>Backups</button>
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
<div class="navbar-main">
|
<div class="navbar-main">
|
||||||
|
<a class="{{ request()->routeIs('project.service') ? 'text-white' : '' }}"
|
||||||
|
href="{{ route('project.service', $parameters) }}">
|
||||||
|
<button>Configuration</button>
|
||||||
|
</a>
|
||||||
<x-services.links :service="$service" />
|
<x-services.links :service="$service" />
|
||||||
<div class="flex-1"></div>
|
<div class="flex-1"></div>
|
||||||
@if (serviceStatus($service) === 'degraded')
|
@if (serviceStatus($service) === 'degraded')
|
||||||
|
@ -24,7 +24,8 @@
|
|||||||
<div>Configuration</div>
|
<div>Configuration</div>
|
||||||
</div>
|
</div>
|
||||||
<x-forms.button type="submit">Save</x-forms.button>
|
<x-forms.button type="submit">Save</x-forms.button>
|
||||||
<x-forms.button class="w-64" onclick="composeModal.showModal()">Edit Compose File</x-forms.button>
|
<x-forms.button class="w-64" onclick="composeModal.showModal()">Edit Compose
|
||||||
|
File</x-forms.button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<x-forms.input id="service.name" required label="Service Name"
|
<x-forms.input id="service.name" required label="Service Name"
|
||||||
@ -34,16 +35,18 @@
|
|||||||
</form>
|
</form>
|
||||||
<div class="grid grid-cols-1 gap-2 pt-4 xl:grid-cols-3">
|
<div class="grid grid-cols-1 gap-2 pt-4 xl:grid-cols-3">
|
||||||
@foreach ($service->applications as $application)
|
@foreach ($service->applications as $application)
|
||||||
<a @class([
|
<div @class([
|
||||||
'border-l border-dashed border-red-500' => Str::of(
|
'border-l border-dashed border-red-500' => Str::of(
|
||||||
$application->status)->contains(['exited']),
|
$application->status)->contains(['exited']),
|
||||||
'border-l border-dashed border-success' => Str::of(
|
'border-l border-dashed border-success' => Str::of(
|
||||||
$application->status)->contains(['running']),
|
$application->status)->contains(['running']),
|
||||||
'border-l border-dashed border-warning' => Str::of(
|
'border-l border-dashed border-warning' => Str::of(
|
||||||
$application->status)->contains(['starting']),
|
$application->status)->contains(['starting']),
|
||||||
'flex flex-col justify-center box',
|
'flex gap-2 box group',
|
||||||
])
|
])>
|
||||||
|
<a class="flex flex-col flex-1 group-hover:text-white hover:no-underline"
|
||||||
href="{{ route('project.service.show', [...$parameters, 'service_name' => $application->name]) }}">
|
href="{{ route('project.service.show', [...$parameters, 'service_name' => $application->name]) }}">
|
||||||
|
|
||||||
@if ($application->human_name)
|
@if ($application->human_name)
|
||||||
{{ Str::headline($application->human_name) }}
|
{{ Str::headline($application->human_name) }}
|
||||||
@else
|
@else
|
||||||
@ -60,17 +63,21 @@
|
|||||||
@endif
|
@endif
|
||||||
<div class="text-xs">{{ $application->status }}</div>
|
<div class="text-xs">{{ $application->status }}</div>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="flex gap-2 p-1 mx-4 text-xs font-bold rounded hover:no-underline hover:text-warning"
|
||||||
|
href="{{ route('project.service.logs', [...$parameters, 'service_name' => $application->name]) }}">Logs</a>
|
||||||
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
@foreach ($databases as $database)
|
@foreach ($databases as $database)
|
||||||
<a @class([
|
<div @class([
|
||||||
'border-l border-dashed border-red-500' => Str::of(
|
'border-l border-dashed border-red-500' => Str::of(
|
||||||
$database->status)->contains(['exited']),
|
$database->status)->contains(['exited']),
|
||||||
'border-l border-dashed border-success' => Str::of(
|
'border-l border-dashed border-success' => Str::of(
|
||||||
$database->status)->contains(['running']),
|
$database->status)->contains(['running']),
|
||||||
'border-l border-dashed border-warning' => Str::of(
|
'border-l border-dashed border-warning' => Str::of(
|
||||||
$database->status)->contains(['restarting']),
|
$database->status)->contains(['restarting']),
|
||||||
'flex flex-col justify-center box',
|
'flex gap-2 box group',
|
||||||
])
|
])>
|
||||||
|
<a class="flex flex-col flex-1 group-hover:text-white hover:no-underline"
|
||||||
href="{{ route('project.service.show', [...$parameters, 'service_name' => $database->name]) }}">
|
href="{{ route('project.service.show', [...$parameters, 'service_name' => $database->name]) }}">
|
||||||
@if ($database->human_name)
|
@if ($database->human_name)
|
||||||
{{ Str::headline($database->human_name) }}
|
{{ Str::headline($database->human_name) }}
|
||||||
@ -85,6 +92,9 @@
|
|||||||
@endif
|
@endif
|
||||||
<div class="text-xs">{{ $database->status }}</div>
|
<div class="text-xs">{{ $database->status }}</div>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="flex gap-2 p-1 mx-4 text-xs font-bold rounded hover:no-underline hover:text-warning"
|
||||||
|
href="{{ route('project.service.logs', [...$parameters, 'service_name' => $database->name]) }}">Logs</a>
|
||||||
|
</div>
|
||||||
@endforeach
|
@endforeach
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -11,6 +11,12 @@
|
|||||||
<a :class="activeTab === 'storages' && 'text-white'"
|
<a :class="activeTab === 'storages' && 'text-white'"
|
||||||
@click.prevent="activeTab = 'storages'; window.location.hash = 'storages'" href="#">Storages
|
@click.prevent="activeTab = 'storages'; window.location.hash = 'storages'" href="#">Storages
|
||||||
</a>
|
</a>
|
||||||
|
@if (data_get($parameters, 'service_name'))
|
||||||
|
<a class="{{ request()->routeIs('project.service.logs') ? 'text-white' : '' }}"
|
||||||
|
href="{{ route('project.service.logs', $parameters) }}">
|
||||||
|
<button>Logs</button>
|
||||||
|
</a>
|
||||||
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full pl-8">
|
<div class="w-full pl-8">
|
||||||
@isset($serviceApplication)
|
@isset($serviceApplication)
|
||||||
@ -32,7 +38,6 @@
|
|||||||
@isset($serviceDatabase)
|
@isset($serviceDatabase)
|
||||||
<div x-cloak x-show="activeTab === 'general'" class="h-full">
|
<div x-cloak x-show="activeTab === 'general'" class="h-full">
|
||||||
<livewire:project.service.database :database="$serviceDatabase" />
|
<livewire:project.service.database :database="$serviceDatabase" />
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div x-cloak x-show="activeTab === 'storages'">
|
<div x-cloak x-show="activeTab === 'storages'">
|
||||||
<livewire:project.shared.storages.all :resource="$serviceDatabase" />
|
<livewire:project.shared.storages.all :resource="$serviceDatabase" />
|
||||||
|
18
resources/views/livewire/project/shared/get-logs.blade.php
Normal file
18
resources/views/livewire/project/shared/get-logs.blade.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<div x-init="$wire.getLogs">
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<h2>Logs</h2>
|
||||||
|
@if ($streamLogs)
|
||||||
|
<span wire:poll.1000ms='getLogs(true)' class="loading loading-xs text-warning loading-spinner"></span>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
<div class="w-32">
|
||||||
|
<x-forms.checkbox instantSave label="Stream Logs" id="streamLogs"></x-forms.checkbox>
|
||||||
|
</div>
|
||||||
|
<div class="container w-full pt-4 mx-auto">
|
||||||
|
<div
|
||||||
|
class="scrollbar flex flex-col-reverse w-full overflow-y-auto border border-solid rounded border-coolgray-300 max-h-[32rem] p-4 pt-6 text-xs text-white">
|
||||||
|
|
||||||
|
<pre class="font-mono whitespace-pre-wrap">{{ $outputs }}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
41
resources/views/livewire/project/shared/logs.blade.php
Normal file
41
resources/views/livewire/project/shared/logs.blade.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
<x-layout>
|
||||||
|
@if ($type === 'application')
|
||||||
|
<h1>Logs</h1>
|
||||||
|
<livewire:project.application.heading :application="$resource" />
|
||||||
|
<div class="pt-4">
|
||||||
|
@if (Str::of($status)->startsWith('running'))
|
||||||
|
<livewire:project.shared.get-logs :server="$server" :container="$container" />
|
||||||
|
@else
|
||||||
|
Application is not running.
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@elseif ($type === 'database')
|
||||||
|
<h1>Logs</h1>
|
||||||
|
<livewire:project.database.heading :database="$resource" />
|
||||||
|
<div class="pt-4">
|
||||||
|
@if (Str::of($status)->startsWith('running'))
|
||||||
|
<livewire:project.shared.get-logs :server="$server" :container="$container" />
|
||||||
|
@else
|
||||||
|
Database is not running.
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
@elseif ($type === 'service')
|
||||||
|
<livewire:project.service.navbar :service="$resource" :parameters="$parameters" :query="$query" />
|
||||||
|
<div class="flex gap-4 pt-6">
|
||||||
|
<div>
|
||||||
|
<a class="{{ request()->routeIs('project.service.show') ? 'text-white' : '' }}"
|
||||||
|
href="{{ route('project.service.show', $parameters) }}">
|
||||||
|
<button><- Back</button>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 pl-8">
|
||||||
|
@if (Str::of($status)->startsWith('running'))
|
||||||
|
<livewire:project.shared.get-logs :server="$server" :container="$container" />
|
||||||
|
@else
|
||||||
|
Service is not running.
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
</x-layout>
|
@ -10,6 +10,7 @@ use App\Http\Livewire\Boarding\Index as BoardingIndex;
|
|||||||
use App\Http\Livewire\Project\Service\Index as ServiceIndex;
|
use App\Http\Livewire\Project\Service\Index as ServiceIndex;
|
||||||
use App\Http\Livewire\Project\Service\Show as ServiceShow;
|
use App\Http\Livewire\Project\Service\Show as ServiceShow;
|
||||||
use App\Http\Livewire\Dashboard;
|
use App\Http\Livewire\Dashboard;
|
||||||
|
use App\Http\Livewire\Project\Shared\Logs;
|
||||||
use App\Http\Livewire\Server\All;
|
use App\Http\Livewire\Server\All;
|
||||||
use App\Http\Livewire\Server\Show;
|
use App\Http\Livewire\Server\Show;
|
||||||
use App\Http\Livewire\Waitlist\Index as WaitlistIndex;
|
use App\Http\Livewire\Waitlist\Index as WaitlistIndex;
|
||||||
@ -80,14 +81,20 @@ Route::middleware(['auth'])->group(function () {
|
|||||||
[ApplicationController::class, 'deployment']
|
[ApplicationController::class, 'deployment']
|
||||||
)->name('project.application.deployment');
|
)->name('project.application.deployment');
|
||||||
|
|
||||||
|
Route::get('/project/{project_uuid}/{environment_name}/application/{application_uuid}/logs', Logs::class)->name('project.application.logs');
|
||||||
|
|
||||||
// Databases
|
// Databases
|
||||||
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}', [DatabaseController::class, 'configuration'])->name('project.database.configuration');
|
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}', [DatabaseController::class, 'configuration'])->name('project.database.configuration');
|
||||||
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}/backups', [DatabaseController::class, 'backups'])->name('project.database.backups.all');
|
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}/backups', [DatabaseController::class, 'backups'])->name('project.database.backups.all');
|
||||||
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}/backups/{backup_uuid}', [DatabaseController::class, 'executions'])->name('project.database.backups.executions');
|
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}/backups/{backup_uuid}', [DatabaseController::class, 'executions'])->name('project.database.backups.executions');
|
||||||
|
Route::get('/project/{project_uuid}/{environment_name}/database/{database_uuid}/logs', Logs::class)->name('project.database.logs');
|
||||||
|
|
||||||
|
|
||||||
// Services
|
// Services
|
||||||
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}', ServiceIndex::class)->name('project.service');
|
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}', ServiceIndex::class)->name('project.service');
|
||||||
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}/{service_name}', ServiceShow::class)->name('project.service.show');
|
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}/{service_name}', ServiceShow::class)->name('project.service.show');
|
||||||
|
Route::get('/project/{project_uuid}/{environment_name}/service/{service_uuid}/{service_name}/logs', Logs::class)->name('project.service.logs');
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(['auth'])->group(function () {
|
Route::middleware(['auth'])->group(function () {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user