| @@ -69,7 +69,7 @@ class StartMariadb | ||||
|                 ] | ||||
|             ] | ||||
|         ]; | ||||
|         if ($this->database->destination->server->isDrainLogActivated()) { | ||||
|         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { | ||||
|             $docker_compose['services'][$container_name]['logging'] = [ | ||||
|                 'driver' => 'fluentd', | ||||
|                 'options' => [ | ||||
|   | ||||
| @@ -76,7 +76,7 @@ class StartMongodb | ||||
|                 ] | ||||
|             ] | ||||
|         ]; | ||||
|         if ($this->database->destination->server->isDrainLogActivated()) { | ||||
|         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { | ||||
|             $docker_compose['services'][$container_name]['logging'] = [ | ||||
|                 'driver' => 'fluentd', | ||||
|                 'options' => [ | ||||
|   | ||||
| @@ -69,7 +69,7 @@ class StartMysql | ||||
|                 ] | ||||
|             ] | ||||
|         ]; | ||||
|         if ($this->database->destination->server->isDrainLogActivated()) { | ||||
|         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { | ||||
|             $docker_compose['services'][$container_name]['logging'] = [ | ||||
|                 'driver' => 'fluentd', | ||||
|                 'options' => [ | ||||
|   | ||||
| @@ -79,7 +79,8 @@ class StartPostgresql | ||||
|                 ] | ||||
|             ] | ||||
|         ]; | ||||
|         if ($this->database->destination->server->isDrainLogActivated()) { | ||||
|         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { | ||||
|             ray('Log Drain Enabled'); | ||||
|             $docker_compose['services'][$container_name]['logging'] = [ | ||||
|                 'driver' => 'fluentd', | ||||
|                 'options' => [ | ||||
|   | ||||
| @@ -78,7 +78,7 @@ class StartRedis | ||||
|                 ] | ||||
|             ] | ||||
|         ]; | ||||
|         if ($this->database->destination->server->isDrainLogActivated()) { | ||||
|         if ($this->database->destination->server->isLogDrainEnabled() && $this->database->isLogDrainEnabled()) { | ||||
|             $docker_compose['services'][$container_name]['logging'] = [ | ||||
|                 'driver' => 'fluentd', | ||||
|                 'options' => [ | ||||
| @@ -166,6 +166,5 @@ class StartRedis | ||||
|         $content = $this->database->redis_conf; | ||||
|         $content_base64 = base64_encode($content); | ||||
|         $this->commands[] = "echo '{$content_base64}' | base64 -d > $this->configuration_dir/{$filename}"; | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -8,8 +8,17 @@ use App\Models\Server; | ||||
| class InstallLogDrain | ||||
| { | ||||
|     use AsAction; | ||||
|     public function handle(Server $server, string $type) | ||||
|     public function handle(Server $server) | ||||
|     { | ||||
|         if ($server->settings->is_logdrain_newrelic_enabled) { | ||||
|             $type = 'newrelic'; | ||||
|         } else if ($server->settings->is_logdrain_highlight_enabled) { | ||||
|             $type = 'highlight'; | ||||
|         } else if ($server->settings->is_logdrain_axiom_enabled) { | ||||
|             $type = 'axiom'; | ||||
|         } else { | ||||
|             $type = 'none'; | ||||
|         } | ||||
|         try { | ||||
|             if ($type === 'none') { | ||||
|                 $command = [ | ||||
| @@ -127,6 +136,7 @@ services: | ||||
|       - ./parsers.conf:/parsers.conf | ||||
|     ports: | ||||
|       - 127.0.0.1:24224:24224 | ||||
|     restart: unless-stopped | ||||
| ");
 | ||||
|             $readme = base64_encode('# New Relic Log Drain
 | ||||
| This log drain is based on [Fluent Bit](https://fluentbit.io/) and New Relic Log Forwarder. | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
| 
 | ||||
| namespace App\Console; | ||||
| 
 | ||||
| use App\Jobs\CheckLogDrainContainerJob; | ||||
| use App\Jobs\CleanupInstanceStuffsJob; | ||||
| use App\Jobs\DatabaseBackupJob; | ||||
| use App\Jobs\InstanceAutoUpdateJob; | ||||
| @@ -61,6 +62,9 @@ class Kernel extends ConsoleKernel | ||||
|         foreach ($servers as $server) { | ||||
|             $schedule->job(new ServerStatusJob($server))->everyTenMinutes()->onOneServer(); | ||||
|             $schedule->job(new ContainerStatusJob($server))->everyMinute()->onOneServer(); | ||||
|             if ($server->isLogDrainEnabled()) { | ||||
|                 $schedule->job(new CheckLogDrainContainerJob($server))->everyMinute()->onOneServer(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     private function instance_auto_update($schedule) | ||||
|   | ||||
| @@ -32,7 +32,7 @@ class General extends Component | ||||
|     public bool $is_preview_deployments_enabled; | ||||
|     public bool $is_auto_deploy_enabled; | ||||
|     public bool $is_force_https_enabled; | ||||
| 
 | ||||
|     public bool $is_log_drain_enabled; | ||||
| 
 | ||||
|     protected $rules = [ | ||||
|         'application.name' => 'required', | ||||
| @@ -101,6 +101,7 @@ class General extends Component | ||||
|             $this->is_preview_deployments_enabled = $this->application->settings->is_preview_deployments_enabled; | ||||
|             $this->is_auto_deploy_enabled = $this->application->settings->is_auto_deploy_enabled; | ||||
|             $this->is_force_https_enabled = $this->application->settings->is_force_https_enabled; | ||||
|             $this->is_log_drain_enabled = $this->application->settings->is_log_drain_enabled; | ||||
|         } | ||||
|         $this->checkLabelUpdates(); | ||||
|     } | ||||
| @@ -136,6 +137,14 @@ class General extends Component | ||||
|         $this->application->settings->is_preview_deployments_enabled = $this->is_preview_deployments_enabled; | ||||
|         $this->application->settings->is_auto_deploy_enabled = $this->is_auto_deploy_enabled; | ||||
|         $this->application->settings->is_force_https_enabled = $this->is_force_https_enabled; | ||||
|         $this->application->settings->is_log_drain_enabled = $this->is_log_drain_enabled; | ||||
|         if ($this->is_log_drain_enabled) { | ||||
|             if (!$this->application->destination->server->isLogDrainEnabled()) { | ||||
|                 $this->application->settings->is_log_drain_enabled =  $this->is_log_drain_enabled = false; | ||||
|                 $this->emit('error', 'Log drain is not enabled on the server. Please enable it first.'); | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|         $this->application->settings->save(); | ||||
|         $this->application->save(); | ||||
|         $this->application->refresh(); | ||||
|   | ||||
| @@ -28,6 +28,7 @@ class General extends Component | ||||
|         'database.ports_mappings' => 'nullable', | ||||
|         'database.is_public' => 'nullable|boolean', | ||||
|         'database.public_port' => 'nullable|integer', | ||||
|         'database.is_log_drain_enabled' => 'nullable|boolean', | ||||
|     ]; | ||||
|     protected $validationAttributes = [ | ||||
|         'database.name' => 'Name', | ||||
| @@ -50,6 +51,20 @@ class General extends Component | ||||
|             $this->db_url_public = $this->database->getDbUrl(); | ||||
|         } | ||||
|     } | ||||
|     public function instantSaveAdvanced() { | ||||
|         try { | ||||
|             if (!$this->database->destination->server->isLogDrainEnabled()) { | ||||
|                 $this->database->is_log_drain_enabled = false; | ||||
|                 $this->emit('error', 'Log drain is not enabled on the server. Please enable it first.'); | ||||
|                 return; | ||||
|             } | ||||
|             $this->database->save(); | ||||
|             $this->emit('success', 'Database updated successfully.'); | ||||
|             $this->emit('success', 'You need to restart the service for the changes to take effect.'); | ||||
|         } catch (Exception $e) { | ||||
|             return handleError($e, $this); | ||||
|         } | ||||
|     } | ||||
|     public function submit() | ||||
|     { | ||||
|         try { | ||||
|   | ||||
| @@ -27,6 +27,7 @@ class General extends Component | ||||
|         'database.ports_mappings' => 'nullable', | ||||
|         'database.is_public' => 'nullable|boolean', | ||||
|         'database.public_port' => 'nullable|integer', | ||||
|         'database.is_log_drain_enabled' => 'nullable|boolean', | ||||
|     ]; | ||||
|     protected $validationAttributes = [ | ||||
|         'database.name' => 'Name', | ||||
| @@ -48,7 +49,21 @@ class General extends Component | ||||
|             $this->db_url_public = $this->database->getDbUrl(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public function instantSaveAdvanced() | ||||
|     { | ||||
|         try { | ||||
|             if (!$this->database->destination->server->isLogDrainEnabled()) { | ||||
|                 $this->database->is_log_drain_enabled = false; | ||||
|                 $this->emit('error', 'Log drain is not enabled on the server. Please enable it first.'); | ||||
|                 return; | ||||
|             } | ||||
|             $this->database->save(); | ||||
|             $this->emit('success', 'Database updated successfully.'); | ||||
|             $this->emit('success', 'You need to restart the service for the changes to take effect.'); | ||||
|         } catch (Exception $e) { | ||||
|             return handleError($e, $this); | ||||
|         } | ||||
|     } | ||||
|     public function submit() | ||||
|     { | ||||
|         try { | ||||
|   | ||||
| @@ -28,6 +28,7 @@ class General extends Component | ||||
|         'database.ports_mappings' => 'nullable', | ||||
|         'database.is_public' => 'nullable|boolean', | ||||
|         'database.public_port' => 'nullable|integer', | ||||
|         'database.is_log_drain_enabled' => 'nullable|boolean', | ||||
|     ]; | ||||
|     protected $validationAttributes = [ | ||||
|         'database.name' => 'Name', | ||||
| @@ -50,6 +51,21 @@ class General extends Component | ||||
|             $this->db_url_public = $this->database->getDbUrl(); | ||||
|         } | ||||
|     } | ||||
|     public function instantSaveAdvanced() | ||||
|     { | ||||
|         try { | ||||
|             if (!$this->database->destination->server->isLogDrainEnabled()) { | ||||
|                 $this->database->is_log_drain_enabled = false; | ||||
|                 $this->emit('error', 'Log drain is not enabled on the server. Please enable it first.'); | ||||
|                 return; | ||||
|             } | ||||
|             $this->database->save(); | ||||
|             $this->emit('success', 'Database updated successfully.'); | ||||
|             $this->emit('success', 'You need to restart the service for the changes to take effect.'); | ||||
|         } catch (Exception $e) { | ||||
|             return handleError($e, $this); | ||||
|         } | ||||
|     } | ||||
|     public function submit() | ||||
|     { | ||||
|         try { | ||||
|   | ||||
| @@ -34,6 +34,7 @@ class General extends Component | ||||
|         'database.ports_mappings' => 'nullable', | ||||
|         'database.is_public' => 'nullable|boolean', | ||||
|         'database.public_port' => 'nullable|integer', | ||||
|         'database.is_log_drain_enabled' => 'nullable|boolean', | ||||
|     ]; | ||||
|     protected $validationAttributes = [ | ||||
|         'database.name' => 'Name', | ||||
| @@ -57,6 +58,20 @@ class General extends Component | ||||
|             $this->db_url_public = $this->database->getDbUrl(); | ||||
|         } | ||||
|     } | ||||
|     public function instantSaveAdvanced() { | ||||
|         try { | ||||
|             if (!$this->database->destination->server->isLogDrainEnabled()) { | ||||
|                 $this->database->is_log_drain_enabled = false; | ||||
|                 $this->emit('error', 'Log drain is not enabled on the server. Please enable it first.'); | ||||
|                 return; | ||||
|             } | ||||
|             $this->database->save(); | ||||
|             $this->emit('success', 'Database updated successfully.'); | ||||
|             $this->emit('success', 'You need to restart the service for the changes to take effect.'); | ||||
|         } catch (Exception $e) { | ||||
|             return handleError($e, $this); | ||||
|         } | ||||
|     } | ||||
|     public function instantSave() | ||||
|     { | ||||
|         try { | ||||
|   | ||||
| @@ -25,6 +25,7 @@ class General extends Component | ||||
|         'database.ports_mappings' => 'nullable', | ||||
|         'database.is_public' => 'nullable|boolean', | ||||
|         'database.public_port' => 'nullable|integer', | ||||
|         'database.is_log_drain_enabled' => 'nullable|boolean', | ||||
|     ]; | ||||
|     protected $validationAttributes = [ | ||||
|         'database.name' => 'Name', | ||||
| @@ -43,6 +44,20 @@ class General extends Component | ||||
|             $this->db_url_public = $this->database->getDbUrl(); | ||||
|         } | ||||
|     } | ||||
|     public function instantSaveAdvanced() { | ||||
|         try { | ||||
|             if (!$this->database->destination->server->isLogDrainEnabled()) { | ||||
|                 $this->database->is_log_drain_enabled = false; | ||||
|                 $this->emit('error', 'Log drain is not enabled on the server. Please enable it first.'); | ||||
|                 return; | ||||
|             } | ||||
|             $this->database->save(); | ||||
|             $this->emit('success', 'Database updated successfully.'); | ||||
|             $this->emit('success', 'You need to restart the service for the changes to take effect.'); | ||||
|         } catch (Exception $e) { | ||||
|             return handleError($e, $this); | ||||
|         } | ||||
|     } | ||||
|     public function submit() | ||||
|     { | ||||
|         try { | ||||
|   | ||||
| @@ -16,6 +16,7 @@ class Application extends Component | ||||
|         'application.image' => 'required', | ||||
|         'application.exclude_from_status' => 'required|boolean', | ||||
|         'application.required_fqdn' => 'required|boolean', | ||||
|         'application.is_log_drain_enabled' => 'nullable|boolean', | ||||
|     ]; | ||||
|     public function render() | ||||
|     { | ||||
| @@ -25,7 +26,11 @@ class Application extends Component | ||||
|     { | ||||
|         $this->submit(); | ||||
|     } | ||||
| 
 | ||||
|     public function instantSaveAdvanced() | ||||
|     { | ||||
|         $this->submit(); | ||||
|         $this->emit('success', 'You need to restart the service for the changes to take effect.'); | ||||
|     } | ||||
|     public function delete() | ||||
|     { | ||||
|         try { | ||||
| @@ -44,6 +49,11 @@ class Application extends Component | ||||
|     { | ||||
|         try { | ||||
|             $this->validate(); | ||||
|             if (!$this->application->service->destination->server->isLogDrainEnabled()) { | ||||
|                 $this->application->is_log_drain_enabled = false; | ||||
|                 $this->emit('error', 'Log drain is not enabled on the server. Please enable it first.'); | ||||
|                 return; | ||||
|             } | ||||
|             $this->application->save(); | ||||
|             updateCompose($this->application); | ||||
|             $this->emit('success', 'Application saved successfully.'); | ||||
|   | ||||
| @@ -21,18 +21,31 @@ class Database extends Component | ||||
|         'database.exclude_from_status' => 'required|boolean', | ||||
|         'database.public_port' => 'nullable|integer', | ||||
|         'database.is_public' => 'required|boolean', | ||||
|         'database.is_log_drain_enabled' => 'required|boolean', | ||||
|     ]; | ||||
|     public function render() | ||||
|     { | ||||
|         return view('livewire.project.service.database'); | ||||
|     } | ||||
|     public function mount() { | ||||
|     public function mount() | ||||
|     { | ||||
|         if ($this->database->is_public) { | ||||
|             $this->db_url_public = $this->database->getServiceDatabaseUrl(); | ||||
|         } | ||||
|         $this->refreshFileStorages(); | ||||
|     } | ||||
|     public function instantSave() { | ||||
|     public function instantSaveAdvanced() | ||||
|     { | ||||
|         if (!$this->database->service->destination->server->isLogDrainEnabled()) { | ||||
|             $this->database->is_log_drain_enabled = false; | ||||
|             $this->emit('error', 'Log drain is not enabled on the server. Please enable it first.'); | ||||
|             return; | ||||
|         } | ||||
|         $this->submit(); | ||||
|         $this->emit('success', 'You need to restart the service for the changes to take effect.'); | ||||
|     } | ||||
|     public function instantSave() | ||||
|     { | ||||
|         if ($this->database->is_public && !$this->database->public_port) { | ||||
|             $this->emit('error', 'Public port is required.'); | ||||
|             $this->database->is_public = false; | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
| 
 | ||||
| namespace App\Http\Livewire\Server; | ||||
| 
 | ||||
| use App\Actions\Server\InstallLogDrain; | ||||
| use App\Models\Server; | ||||
| use Livewire\Component; | ||||
| 
 | ||||
| @@ -46,14 +47,8 @@ class LogDrains extends Component | ||||
|     public function configureLogDrain() | ||||
|     { | ||||
|         try { | ||||
|             if ($this->server->settings->is_logdrain_newrelic_enabled) { | ||||
|                 $this->server->logDrain('newrelic'); | ||||
|             } else if ($this->server->settings->is_logdrain_highlight_enabled) { | ||||
|                 $this->server->logDrain('highlight'); | ||||
|             } else if ($this->server->settings->is_logdrain_axiom_enabled) { | ||||
|                 $this->server->logDrain('axiom'); | ||||
|             } else { | ||||
|                 $this->server->logDrain('none'); | ||||
|             InstallLogDrain::run($this->server); | ||||
|             if (!$this->server->isLogDrainEnabled()) { | ||||
|                 $this->emit('serverRefresh'); | ||||
|                 $this->emit('success', 'Log drain service stopped.'); | ||||
|                 return; | ||||
|   | ||||
| @@ -864,7 +864,7 @@ class ApplicationDeploymentJob implements ShouldQueue, ShouldBeEncrypted | ||||
|                 ] | ||||
|             ] | ||||
|         ]; | ||||
|         if ($this->server->isDrainLogActivated()) { | ||||
|         if ($this->server->isLogDrainEnabled() && $this->application->isLogDrainEnabled()) { | ||||
|             $docker_compose['services'][$this->container_name]['logging'] = [ | ||||
|                 'driver' => 'fluentd', | ||||
|                 'options' => [ | ||||
|   | ||||
							
								
								
									
										88
									
								
								app/Jobs/CheckLogDrainContainerJob.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								app/Jobs/CheckLogDrainContainerJob.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | ||||
| <?php | ||||
| 
 | ||||
| namespace App\Jobs; | ||||
| 
 | ||||
| use App\Actions\Server\InstallLogDrain; | ||||
| use App\Models\Server; | ||||
| use App\Notifications\Container\ContainerRestarted; | ||||
| use App\Notifications\Container\ContainerStopped; | ||||
| use Illuminate\Bus\Queueable; | ||||
| use Illuminate\Contracts\Queue\ShouldBeEncrypted; | ||||
| use Illuminate\Contracts\Queue\ShouldQueue; | ||||
| use Illuminate\Foundation\Bus\Dispatchable; | ||||
| use Illuminate\Queue\InteractsWithQueue; | ||||
| use Illuminate\Queue\Middleware\WithoutOverlapping; | ||||
| use Illuminate\Queue\SerializesModels; | ||||
| use Illuminate\Support\Sleep; | ||||
| 
 | ||||
| class CheckLogDrainContainerJob implements ShouldQueue, ShouldBeEncrypted | ||||
| { | ||||
|     use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; | ||||
| 
 | ||||
|     public function __construct(public Server $server) | ||||
|     { | ||||
|     } | ||||
|     public function middleware(): array | ||||
|     { | ||||
|         return [(new WithoutOverlapping($this->server->id))->dontRelease()]; | ||||
|     } | ||||
| 
 | ||||
|     public function uniqueId(): int | ||||
|     { | ||||
|         return $this->server->id; | ||||
|     } | ||||
|     public function healthcheck() | ||||
|     { | ||||
|         $status = instant_remote_process(["docker inspect --format='{{json .State.Status}}' coolify-log-drain"], $this->server, false); | ||||
|         if (str($status)->contains('running')) { | ||||
|             return true; | ||||
|         } else { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|     public function handle(): void | ||||
|     { | ||||
|         // ray("checking log drain statuses for {$this->server->id}");
 | ||||
|         try { | ||||
|             if (!$this->server->isServerReady()) { | ||||
|                 return; | ||||
|             }; | ||||
|             $containers = instant_remote_process(["docker container ls -q"], $this->server); | ||||
|             if (!$containers) { | ||||
|                 return; | ||||
|             } | ||||
|             $containers = instant_remote_process(["docker container inspect $(docker container ls -q) --format '{{json .}}'"], $this->server); | ||||
|             $containers = format_docker_command_output_to_json($containers); | ||||
| 
 | ||||
|             $foundLogDrainContainer = $containers->filter(function ($value, $key) { | ||||
|                 return data_get($value, 'Name') === '/coolify-log-drain'; | ||||
|             })->first(); | ||||
|             if (!$foundLogDrainContainer || !$this->healthcheck()) { | ||||
|                 ray('Log drain container not found or unhealthy. Restarting...'); | ||||
|                 InstallLogDrain::run($this->server); | ||||
|                 Sleep::for(10)->seconds(); | ||||
|                 if ($this->healthcheck()) { | ||||
|                     if ($this->server->log_drain_notification_sent) { | ||||
|                         $this->server->team->notify(new ContainerRestarted('Coolify Log Drainer', $this->server)); | ||||
|                         $this->server->update(['log_drain_notification_sent' => false]); | ||||
|                     } | ||||
|                     return; | ||||
|                 } | ||||
|                 if (!$this->server->log_drain_notification_sent) { | ||||
|                     ray('Log drain container still unhealthy. Sending notification...'); | ||||
|                     $this->server->team->notify(new ContainerStopped('Coolify Log Drainer', $this->server, null)); | ||||
|                     $this->server->update(['log_drain_notification_sent' => true]); | ||||
|                 } | ||||
|             } else { | ||||
|                 if ($this->server->log_drain_notification_sent) { | ||||
|                     $this->server->team->notify(new ContainerRestarted('Coolify Log Drainer', $this->server)); | ||||
|                     $this->server->update(['log_drain_notification_sent' => false]); | ||||
|                 } | ||||
|             } | ||||
|         } catch (\Throwable $e) { | ||||
|             send_internal_notification("CheckLogDrainContainerJob failed on ({$this->server->id}) with: " . $e->getMessage()); | ||||
|             ray($e->getMessage()); | ||||
|             handleError($e); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -52,29 +52,7 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted | ||||
|             $databases = $this->server->databases(); | ||||
|             $services = $this->server->services()->get(); | ||||
|             $previews = $this->server->previews(); | ||||
|             $this->server->proxyType(); | ||||
|             /// Check if proxy is running
 | ||||
|             $foundProxyContainer = $containers->filter(function ($value, $key) { | ||||
|                 return data_get($value, 'Name') === '/coolify-proxy'; | ||||
|             })->first(); | ||||
|             if (!$foundProxyContainer) { | ||||
|                 try { | ||||
|                     $shouldStart = CheckProxy::run($this->server); | ||||
|                     if ($shouldStart) { | ||||
|                         StartProxy::run($this->server, false); | ||||
|                         $this->server->team->notify(new ContainerRestarted('coolify-proxy', $this->server)); | ||||
|                     } else { | ||||
|                         ray('Proxy could not be started.'); | ||||
|                     } | ||||
|                 } catch (\Throwable $e) { | ||||
|                     ray($e); | ||||
|                 } | ||||
|             } else { | ||||
|                 $this->server->proxy->status = data_get($foundProxyContainer, 'State.Status'); | ||||
|                 $this->server->save(); | ||||
|                 $connectProxyToDockerNetworks = connectProxyToNetworks($this->server); | ||||
|                 instant_remote_process($connectProxyToDockerNetworks, $this->server, false); | ||||
|             } | ||||
| 
 | ||||
|             $foundApplications = []; | ||||
|             $foundApplicationPreviews = []; | ||||
|             $foundDatabases = []; | ||||
| @@ -267,6 +245,30 @@ class ContainerStatusJob implements ShouldQueue, ShouldBeEncrypted | ||||
|                 } | ||||
|                 $this->server->team->notify(new ContainerStopped($containerName, $this->server, $url)); | ||||
|             } | ||||
| 
 | ||||
|             // Check if proxy is running
 | ||||
|             $this->server->proxyType(); | ||||
|             $foundProxyContainer = $containers->filter(function ($value, $key) { | ||||
|                 return data_get($value, 'Name') === '/coolify-proxy'; | ||||
|             })->first(); | ||||
|             if (!$foundProxyContainer) { | ||||
|                 try { | ||||
|                     $shouldStart = CheckProxy::run($this->server); | ||||
|                     if ($shouldStart) { | ||||
|                         StartProxy::run($this->server, false); | ||||
|                         $this->server->team->notify(new ContainerRestarted('coolify-proxy', $this->server)); | ||||
|                     } else { | ||||
|                         ray('Proxy could not be started.'); | ||||
|                     } | ||||
|                 } catch (\Throwable $e) { | ||||
|                     ray($e); | ||||
|                 } | ||||
|             } else { | ||||
|                 $this->server->proxy->status = data_get($foundProxyContainer, 'State.Status'); | ||||
|                 $this->server->save(); | ||||
|                 $connectProxyToDockerNetworks = connectProxyToNetworks($this->server); | ||||
|                 instant_remote_process($connectProxyToDockerNetworks, $this->server, false); | ||||
|             } | ||||
|         } catch (\Throwable $e) { | ||||
|             send_internal_notification("ContainerStatusJob failed on ({$this->server->id}) with: " . $e->getMessage()); | ||||
|             ray($e->getMessage()); | ||||
|   | ||||
| @@ -300,6 +300,9 @@ class Application extends BaseModel | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|     public function isLogDrainEnabled() { | ||||
|        return data_get($this, 'settings.is_log_drain_enabled', false); | ||||
|     } | ||||
|     public function isConfigurationChanged($save = false) | ||||
|     { | ||||
|         $newConfigHash = $this->fqdn . $this->git_repository . $this->git_branch . $this->git_commit_sha . $this->build_pack . $this->static_image . $this->install_command  . $this->build_command . $this->start_command . $this->port_exposes . $this->port_mappings . $this->base_directory . $this->publish_directory . $this->health_check_path  . $this->health_check_port . $this->health_check_host . $this->health_check_method . $this->health_check_return_code . $this->health_check_scheme . $this->health_check_response_text . $this->health_check_interval . $this->health_check_timeout . $this->health_check_retries . $this->health_check_start_period . $this->health_check_enabled . $this->limits_memory  . $this->limits_swap . $this->limits_swappiness . $this->limits_reservation . $this->limits_cpus . $this->limits_cpuset . $this->limits_cpu_shares . $this->dockerfile . $this->dockerfile_location . $this->custom_labels; | ||||
|   | ||||
| @@ -296,15 +296,11 @@ class Server extends BaseModel | ||||
|         // }
 | ||||
|         return true; | ||||
|     } | ||||
|     public function logDrain($type) | ||||
|     { | ||||
|         InstallLogDrain::run($this, $type); | ||||
|     } | ||||
|     public function isFunctional() | ||||
|     { | ||||
|         return $this->settings->is_reachable && $this->settings->is_usable; | ||||
|     } | ||||
|     public function isDrainLogActivated() | ||||
|     public function isLogDrainEnabled() | ||||
|     { | ||||
|         return $this->settings->is_logdrain_newrelic_enabled || $this->settings->is_logdrain_highlight_enabled || $this->settings->is_logdrain_axiom_enabled; | ||||
|     } | ||||
|   | ||||
| @@ -797,7 +797,7 @@ class Service extends BaseModel | ||||
|                         $serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($this->uuid, $fqdns, true)); | ||||
|                     } | ||||
|                 } | ||||
|                 if ($this->server->isDrainLogActivated()) { | ||||
|                 if ($this->server->isLogDrainEnabled() && $savedService->isLogDrainEnabled()) { | ||||
|                     data_set($service, 'logging', [ | ||||
|                         'driver' => 'fluentd', | ||||
|                         'options' => [ | ||||
|   | ||||
| @@ -18,6 +18,10 @@ class ServiceApplication extends BaseModel | ||||
|             $service->fileStorages()->delete(); | ||||
|         }); | ||||
|     } | ||||
|     public function isLogDrainEnabled() | ||||
|     { | ||||
|         return data_get($this, 'is_log_drain_enabled', false); | ||||
|     } | ||||
|     public function type() | ||||
|     { | ||||
|         return 'service'; | ||||
|   | ||||
| @@ -16,6 +16,10 @@ class ServiceDatabase extends BaseModel | ||||
|             $service->fileStorages()->delete(); | ||||
|         }); | ||||
|     } | ||||
|     public function isLogDrainEnabled() | ||||
|     { | ||||
|         return data_get($this, 'is_log_drain_enabled', false); | ||||
|     } | ||||
|     public function type() | ||||
|     { | ||||
|         return 'service'; | ||||
|   | ||||
| @@ -41,6 +41,10 @@ class StandaloneMariadb extends BaseModel | ||||
|             $database->environment_variables()->delete(); | ||||
|         }); | ||||
|     } | ||||
|     public function isLogDrainEnabled() | ||||
|     { | ||||
|         return data_get($this, 'is_log_drain_enabled', false); | ||||
|     } | ||||
|     public function type(): string | ||||
|     { | ||||
|         return 'standalone-mariadb'; | ||||
|   | ||||
| @@ -44,7 +44,10 @@ class StandaloneMongodb extends BaseModel | ||||
|             $database->environment_variables()->delete(); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     public function isLogDrainEnabled() | ||||
|     { | ||||
|         return data_get($this, 'is_log_drain_enabled', false); | ||||
|     } | ||||
|     public function mongoInitdbRootPassword(): Attribute | ||||
|     { | ||||
|         return Attribute::make( | ||||
|   | ||||
| @@ -46,6 +46,11 @@ class StandaloneMysql extends BaseModel | ||||
|         return 'standalone-mysql'; | ||||
|     } | ||||
| 
 | ||||
|     public function isLogDrainEnabled() | ||||
|     { | ||||
|         return data_get($this, 'is_log_drain_enabled', false); | ||||
|     } | ||||
| 
 | ||||
|     public function portsMappings(): Attribute | ||||
|     { | ||||
|         return Attribute::make( | ||||
|   | ||||
| @@ -42,6 +42,11 @@ class StandalonePostgresql extends BaseModel | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     public function isLogDrainEnabled() | ||||
|     { | ||||
|         return data_get($this, 'is_log_drain_enabled', false); | ||||
|     } | ||||
| 
 | ||||
|     public function portsMappings(): Attribute | ||||
|     { | ||||
|         return Attribute::make( | ||||
|   | ||||
| @@ -37,6 +37,11 @@ class StandaloneRedis extends BaseModel | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     public function isLogDrainEnabled() | ||||
|     { | ||||
|         return data_get($this, 'is_log_drain_enabled', false); | ||||
|     } | ||||
| 
 | ||||
|     public function portsMappings(): Attribute | ||||
|     { | ||||
|         return Attribute::make( | ||||
|   | ||||
| @@ -27,7 +27,7 @@ class ContainerRestarted extends Notification implements ShouldQueue | ||||
|     public function toMail(): MailMessage | ||||
|     { | ||||
|         $mail = new MailMessage(); | ||||
|         $mail->subject("Coolify: Container ({$this->name}) has been restarted automatically on {$this->server->name}"); | ||||
|         $mail->subject("Coolify: A service ({$this->name}) has been restarted automatically on {$this->server->name}"); | ||||
|         $mail->view('emails.container-restarted', [ | ||||
|             'containerName' => $this->name, | ||||
|             'serverName' => $this->server->name, | ||||
| @@ -38,12 +38,12 @@ class ContainerRestarted extends Notification implements ShouldQueue | ||||
| 
 | ||||
|     public function toDiscord(): string | ||||
|     { | ||||
|         $message = "Coolify: Container ({$this->name}) has been restarted automatically on {$this->server->name}"; | ||||
|         $message = "Coolify: A service ({$this->name}) has been restarted automatically on {$this->server->name}"; | ||||
|         return $message; | ||||
|     } | ||||
|     public function toTelegram(): array | ||||
|     { | ||||
|         $message = "Coolify:  Container ({$this->name}) has been restarted automatically on {$this->server->name}"; | ||||
|         $message = "Coolify: A service ({$this->name}) has been restarted automatically on {$this->server->name}"; | ||||
|         $payload = [ | ||||
|             "message" => $message, | ||||
|         ]; | ||||
|   | ||||
| @@ -26,7 +26,7 @@ class ContainerStopped extends Notification implements ShouldQueue | ||||
|     public function toMail(): MailMessage | ||||
|     { | ||||
|         $mail = new MailMessage(); | ||||
|         $mail->subject("Coolify: Container ({$this->name}) has been stopped on {$this->server->name}"); | ||||
|         $mail->subject("Coolify: A service ({$this->name}) has been stopped on {$this->server->name}"); | ||||
|         $mail->view('emails.container-stopped', [ | ||||
|             'containerName' => $this->name, | ||||
|             'serverName' => $this->server->name, | ||||
| @@ -37,12 +37,12 @@ class ContainerStopped extends Notification implements ShouldQueue | ||||
| 
 | ||||
|     public function toDiscord(): string | ||||
|     { | ||||
|         $message = "Coolify:  Container ({$this->name}) has been stopped on {$this->server->name}"; | ||||
|         $message = "Coolify: A service ({$this->name}) has been stopped on {$this->server->name}"; | ||||
|         return $message; | ||||
|     } | ||||
|     public function toTelegram(): array | ||||
|     { | ||||
|         $message = "Coolify:  Container ($this->name} has been stopped on {$this->server->name}"; | ||||
|         $message = "Coolify: A service ($this->name} has been stopped on {$this->server->name}"; | ||||
|         $payload = [ | ||||
|             "message" => $message, | ||||
|         ]; | ||||
|   | ||||
| @@ -7,7 +7,7 @@ return [ | ||||
| 
 | ||||
|     // The release version of your application
 | ||||
|     // Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
 | ||||
|     'release' => '4.0.0-beta.143', | ||||
|     'release' => '4.0.0-beta.144', | ||||
|     // When left empty or `null` the Laravel environment will be used
 | ||||
|     'environment' => config('app.env'), | ||||
| 
 | ||||
|   | ||||
| @@ -1,3 +1,3 @@ | ||||
| <?php | ||||
| 
 | ||||
| return '4.0.0-beta.143'; | ||||
| return '4.0.0-beta.144'; | ||||
|   | ||||
| @@ -0,0 +1,76 @@ | ||||
| <?php | ||||
| 
 | ||||
| use Illuminate\Database\Migrations\Migration; | ||||
| use Illuminate\Database\Schema\Blueprint; | ||||
| use Illuminate\Support\Facades\Schema; | ||||
| 
 | ||||
| return new class extends Migration | ||||
| { | ||||
|     /** | ||||
|      * Run the migrations. | ||||
|      */ | ||||
|     public function up(): void | ||||
|     { | ||||
|         Schema::table('application_settings', function (Blueprint $table) { | ||||
|             $table->boolean('is_log_drain_enabled')->default(false); | ||||
|         }); | ||||
|         Schema::table('standalone_redis', function (Blueprint $table) { | ||||
|             $table->boolean('is_log_drain_enabled')->default(false); | ||||
|         }); | ||||
|         Schema::table('standalone_mysqls', function (Blueprint $table) { | ||||
|             $table->boolean('is_log_drain_enabled')->default(false); | ||||
|         }); | ||||
|         Schema::table('standalone_mariadbs', function (Blueprint $table) { | ||||
|             $table->boolean('is_log_drain_enabled')->default(false); | ||||
|         }); | ||||
|         Schema::table('standalone_postgresqls', function (Blueprint $table) { | ||||
|             $table->boolean('is_log_drain_enabled')->default(false); | ||||
|         }); | ||||
|         Schema::table('standalone_mongodbs', function (Blueprint $table) { | ||||
|             $table->boolean('is_log_drain_enabled')->default(false); | ||||
|         }); | ||||
|         Schema::table('service_applications', function (Blueprint $table) { | ||||
|             $table->boolean('is_log_drain_enabled')->default(false); | ||||
|         }); | ||||
|         Schema::table('service_databases', function (Blueprint $table) { | ||||
|             $table->boolean('is_log_drain_enabled')->default(false); | ||||
|         }); | ||||
|         Schema::table('servers', function (Blueprint $table) { | ||||
|             $table->boolean('log_drain_notification_sent')->default(false); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Reverse the migrations. | ||||
|      */ | ||||
|     public function down(): void | ||||
|     { | ||||
|         Schema::table('application_settings', function (Blueprint $table) { | ||||
|             $table->dropColumn('is_log_drain_enabled'); | ||||
|         }); | ||||
|         Schema::table('standalone_redis', function (Blueprint $table) { | ||||
|             $table->dropColumn('is_log_drain_enabled'); | ||||
|         }); | ||||
|         Schema::table('standalone_mysqls', function (Blueprint $table) { | ||||
|             $table->dropColumn('is_log_drain_enabled'); | ||||
|         }); | ||||
|         Schema::table('standalone_mariadbs', function (Blueprint $table) { | ||||
|             $table->dropColumn('is_log_drain_enabled'); | ||||
|         }); | ||||
|         Schema::table('standalone_postgresqls', function (Blueprint $table) { | ||||
|             $table->dropColumn('is_log_drain_enabled'); | ||||
|         }); | ||||
|         Schema::table('standalone_mongodbs', function (Blueprint $table) { | ||||
|             $table->dropColumn('is_log_drain_enabled'); | ||||
|         }); | ||||
|         Schema::table('service_applications', function (Blueprint $table) { | ||||
|             $table->dropColumn('is_log_drain_enabled'); | ||||
|         }); | ||||
|         Schema::table('service_databases', function (Blueprint $table) { | ||||
|             $table->dropColumn('is_log_drain_enabled'); | ||||
|         }); | ||||
|         Schema::table('servers', function (Blueprint $table) { | ||||
|             $table->dropColumn('log_drain_notification_sent'); | ||||
|         }); | ||||
|     } | ||||
| }; | ||||
| @@ -1,6 +1,6 @@ | ||||
| <x-emails.layout> | ||||
| 
 | ||||
| Container ({{ $containerName }}) has been restarted automatically on {{$serverName}}, because it was stopped unexpectedly. | ||||
| A service ({{ $containerName }}) has been restarted automatically on {{$serverName}}, because it was stopped unexpectedly. | ||||
| 
 | ||||
| @if ($containerName === 'coolify-proxy') | ||||
| Coolify Proxy should run on your server as you have FQDNs set up in one of your resources. | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| <x-emails.layout> | ||||
| 
 | ||||
| Container {{ $containerName }} has been stopped unexpectedly on {{$serverName}}. | ||||
| A service ({{ $containerName }}) has been stopped unexpectedly on {{$serverName}}. | ||||
| 
 | ||||
| @if ($url) | ||||
| Please check what is going on [here]({{ $url }}). | ||||
|   | ||||
| @@ -114,6 +114,8 @@ | ||||
|         </div> | ||||
|         <h3>Advanced</h3> | ||||
|         <div class="flex flex-col"> | ||||
|             <x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings." instantSave | ||||
|                 id="is_log_drain_enabled" label="Drain Logs" /> | ||||
|             <x-forms.checkbox | ||||
|                 helper="Your application will be available only on https if your domain starts with https://..." | ||||
|                 instantSave id="is_force_https_enabled" label="Force Https" /> | ||||
|   | ||||
| @@ -59,5 +59,10 @@ | ||||
|             @endif | ||||
|         </div> | ||||
|         <x-forms.textarea label="Custom MariaDB Configuration" rows="10" id="database.mariadb_conf" /> | ||||
|         <h3 class="pt-4">Advanced</h3> | ||||
|         <div class="flex flex-col"> | ||||
|             <x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings." | ||||
|                 instantSave="instantSaveAdvanced" id="database.is_log_drain_enabled" label="Drain Logs" /> | ||||
|         </div> | ||||
|     </form> | ||||
| </div> | ||||
|   | ||||
| @@ -16,8 +16,8 @@ | ||||
|             <div class="flex gap-2"> | ||||
|                 <x-forms.input label="Initial Username" id="database.mongo_initdb_root_username" | ||||
|                     placeholder="If empty: postgres" readonly helper="You can only change this in the database." /> | ||||
|                 <x-forms.input label="Initial Password" id="database.mongo_initdb_root_password" type="password" required | ||||
|                     readonly helper="You can only change this in the database." /> | ||||
|                 <x-forms.input label="Initial Password" id="database.mongo_initdb_root_password" type="password" | ||||
|                     required readonly helper="You can only change this in the database." /> | ||||
|                 <x-forms.input label="Initial Database" id="database.mongo_initdb_database" | ||||
|                     placeholder="If empty, it will be the same as Username." readonly | ||||
|                     helper="You can only change this in the database." /> | ||||
| @@ -53,5 +53,10 @@ | ||||
|             @endif | ||||
|         </div> | ||||
|         <x-forms.textarea label="Custom MongoDB Configuration" rows="10" id="database.mongo_conf" /> | ||||
|         <h3 class="pt-4">Advanced</h3> | ||||
|         <div class="flex flex-col"> | ||||
|             <x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings." | ||||
|                 instantSave="instantSaveAdvanced" id="database.is_log_drain_enabled" label="Drain Logs" /> | ||||
|         </div> | ||||
|     </form> | ||||
| </div> | ||||
|   | ||||
| @@ -59,5 +59,10 @@ | ||||
|             @endif | ||||
|         </div> | ||||
|         <x-forms.textarea label="Custom Mysql Configuration" rows="10" id="database.mysql_conf" /> | ||||
|         <h3 class="pt-4">Advanced</h3> | ||||
|         <div class="flex flex-col"> | ||||
|             <x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings." | ||||
|                 instantSave="instantSaveAdvanced" id="database.is_log_drain_enabled" label="Drain Logs" /> | ||||
|         </div> | ||||
|     </form> | ||||
| </div> | ||||
|   | ||||
| @@ -74,6 +74,11 @@ | ||||
|         </div> | ||||
|         <x-forms.textarea label="Custom PostgreSQL Configuration" rows="10" id="database.postgres_conf" /> | ||||
|     </form> | ||||
|     <h3 class="pt-4">Advanced</h3> | ||||
|     <div class="flex flex-col"> | ||||
|         <x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings." instantSave="instantSaveAdvanced" | ||||
|             id="database.is_log_drain_enabled" label="Drain Logs" /> | ||||
|     </div> | ||||
|     <div class="pb-16"> | ||||
|         <div class="flex gap-2 pt-4 pb-2"> | ||||
|             <h3>Initialization scripts</h3> | ||||
| @@ -87,4 +92,5 @@ | ||||
|             @endforelse | ||||
|         </div> | ||||
|     </div> | ||||
| 
 | ||||
| </div> | ||||
|   | ||||
| @@ -33,5 +33,10 @@ | ||||
|         <x-forms.textarea | ||||
|             helper="<a target='_blank' class='text-white underline' href='https://raw.githubusercontent.com/redis/redis/7.2/redis.conf'>Redis Default Configuration</a>" | ||||
|             label="Custom Redis Configuration" rows="10" id="database.redis_conf" /> | ||||
|         <h3 class="pt-4">Advanced</h3> | ||||
|         <div class="flex flex-col"> | ||||
|             <x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings." | ||||
|                 instantSave="instantSaveAdvanced" id="database.is_log_drain_enabled" label="Drain Logs" /> | ||||
|         </div> | ||||
|     </form> | ||||
| </div> | ||||
|   | ||||
| @@ -36,6 +36,8 @@ | ||||
|             <x-forms.checkbox instantSave label="Exclude from service status" | ||||
|                 helper="If you do not need to monitor this resource, enable. Useful if this service is optional." | ||||
|                 id="application.exclude_from_status"></x-forms.checkbox> | ||||
|             <x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings." | ||||
|                 instantSave="instantSaveAdvanced" id="application.is_log_drain_enabled" label="Drain Logs" /> | ||||
|         </div> | ||||
|     </form> | ||||
| </div> | ||||
|   | ||||
| @@ -32,6 +32,8 @@ | ||||
|             <x-forms.checkbox instantSave label="Exclude from service status" | ||||
|                 helper="If you do not need to monitor this resource, enable. Useful if this service is optional." | ||||
|                 id="database.exclude_from_status"></x-forms.checkbox> | ||||
|             <x-forms.checkbox helper="Drain logs to your configured log drain endpoint in your Server settings." | ||||
|                 instantSave="instantSaveAdvanced" id="database.is_log_drain_enabled" label="Drain Logs" /> | ||||
|         </div> | ||||
|     </form> | ||||
| </div> | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| <div> | ||||
|     <x-server.navbar :server="$server" :parameters="$parameters" /> | ||||
|     <h2>Log Drains</h2> | ||||
|     <div class="pb-4">Sends resource logs to external services.</div> | ||||
|     <div class="pb-4">Sends service logs to 3rd party tools.</div> | ||||
|     <div class="flex flex-col gap-4 pt-4"> | ||||
|         <div class="p-4 border border-coolgray-500"> | ||||
|             <form wire:submit.prevent='submit("newrelic")' class="flex flex-col"> | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
|             "version": "3.12.36" | ||||
|         }, | ||||
|         "v4": { | ||||
|             "version": "4.0.0-beta.143" | ||||
|             "version": "4.0.0-beta.144" | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Andras Bacsai
					Andras Bacsai