mirror of
https://github.com/cupcakearmy/coolify.git
synced 2024-10-23 00:24:15 +02:00
commit
9c69044da5
35
README.md
35
README.md
@ -10,35 +10,40 @@ # About the Project
|
|||||||
|
|
||||||
For more information, take a look at our landing page [here](https://coolify.io).
|
For more information, take a look at our landing page [here](https://coolify.io).
|
||||||
|
|
||||||
> If you are looking for previous (v3) version, it is [here](https://github.com/coollabsio/coolify/tree/v3).
|
# Donations
|
||||||
|
To stay completely free, open-source, no feature behind paywall and evolve the project, we need your help. If you like Coolify, please consider donating to help us fund the future development of the project.
|
||||||
|
|
||||||
|
https://coolify.io/sponsorships
|
||||||
|
|
||||||
|
Thank you so much!
|
||||||
|
|
||||||
# Cloud
|
# Cloud
|
||||||
|
|
||||||
If you do not want to self-host Coolify, there is a paid cloud version available: https://app.coolify.io
|
If you do not want to self-host Coolify, there is a paid cloud version available: https://app.coolify.io
|
||||||
|
|
||||||
You can easily attach your own servers, get all the automations, free email notifications, etc.
|
|
||||||
|
|
||||||
For more information & pricing, take a look at our landing page [here](https://coolify.io).
|
For more information & pricing, take a look at our landing page [here](https://coolify.io).
|
||||||
|
|
||||||
# Beta
|
## Why should I use the Cloud version?
|
||||||
|
The recommended way to use Coolify is to have one server for Coolify and one (or more) for the resources you are deploying. A server is around 4-5$/month.
|
||||||
|
|
||||||
The latest version (v4) is still in beta. That does not mean it is unstable. All the features that are available are stable enough be usable in real-life.
|
By subscribing to the cloud version, you get the Coolify server for the same price, but with:
|
||||||
|
- High-availability
|
||||||
There are hundreds of people using it for managing their client's applications, freelancers, hobbyists, businesses.
|
- Free email notifications
|
||||||
|
- Better support
|
||||||
|
- Less maintenance for you
|
||||||
|
|
||||||
# Installation
|
# Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
|
curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash
|
||||||
```
|
```
|
||||||
|
You can find the installation script source [here](./scripts/install.sh).
|
||||||
|
|
||||||
You can find the installation script [here](./scripts/install.sh).
|
# Support
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
Contact us [here](https://coolify.io/docs/contact).
|
Contact us [here](https://coolify.io/docs/contact).
|
||||||
|
|
||||||
## Recognitions
|
# Recognitions
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a href="https://news.ycombinator.com/item?id=26624341">
|
<a href="https://news.ycombinator.com/item?id=26624341">
|
||||||
@ -54,11 +59,11 @@ ## Recognitions
|
|||||||
|
|
||||||
<a href="https://trendshift.io/repositories/634" target="_blank"><img src="https://trendshift.io/api/badge/repositories/634" alt="coollabsio%2Fcoolify | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
<a href="https://trendshift.io/repositories/634" target="_blank"><img src="https://trendshift.io/api/badge/repositories/634" alt="coollabsio%2Fcoolify | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||||
|
|
||||||
## 💰 Financial Contributors
|
# 💰 Financial Contributors
|
||||||
|
|
||||||
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/coollabsio/contribute)]
|
Become a financial contributor and help us sustain our community. [[Contribute](https://opencollective.com/coollabsio/contribute)]
|
||||||
|
|
||||||
### Organizations
|
## Organizations
|
||||||
|
|
||||||
Special thanks to our biggest sponsors, [CCCareers](https://cccareers.org/) and [Appwrite](https://appwrite.io)!
|
Special thanks to our biggest sponsors, [CCCareers](https://cccareers.org/) and [Appwrite](https://appwrite.io)!
|
||||||
|
|
||||||
@ -78,10 +83,10 @@ ### Organizations
|
|||||||
<a href="https://opencollective.com/coollabsio/organization/8/website"><img src="https://opencollective.com/coollabsio/organization/8/avatar.svg"></a>
|
<a href="https://opencollective.com/coollabsio/organization/8/website"><img src="https://opencollective.com/coollabsio/organization/8/avatar.svg"></a>
|
||||||
<a href="https://opencollective.com/coollabsio/organization/9/website"><img src="https://opencollective.com/coollabsio/organization/9/avatar.svg"></a>
|
<a href="https://opencollective.com/coollabsio/organization/9/website"><img src="https://opencollective.com/coollabsio/organization/9/avatar.svg"></a>
|
||||||
|
|
||||||
### Individuals
|
## Individuals
|
||||||
|
|
||||||
<a href="https://opencollective.com/coollabsio"><img src="https://opencollective.com/coollabsio/individuals.svg?width=890"></a>
|
<a href="https://opencollective.com/coollabsio"><img src="https://opencollective.com/coollabsio/individuals.svg?width=890"></a>
|
||||||
|
|
||||||
## Star History
|
# Star History
|
||||||
|
|
||||||
[![Star History Chart](https://api.star-history.com/svg?repos=coollabsio/coolify&type=Date)](https://star-history.com/#coollabsio/coolify&Date)
|
[![Star History Chart](https://api.star-history.com/svg?repos=coollabsio/coolify&type=Date)](https://star-history.com/#coollabsio/coolify&Date)
|
||||||
|
@ -69,6 +69,16 @@ public function handle(StandaloneMariadb $database)
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
if ($this->database->destination->server->isDrainLogActivated()) {
|
||||||
|
$docker_compose['services'][$container_name]['logging'] = [
|
||||||
|
'driver' => 'fluentd',
|
||||||
|
'options' => [
|
||||||
|
'fluentd-address' => "tcp://127.0.0.1:24224",
|
||||||
|
'fluentd-async' => "true",
|
||||||
|
'fluentd-sub-second-precision' => "true",
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
if (count($this->database->ports_mappings_array) > 0) {
|
if (count($this->database->ports_mappings_array) > 0) {
|
||||||
$docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
|
$docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,16 @@ public function handle(StandaloneMongodb $database)
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
if ($this->database->destination->server->isDrainLogActivated()) {
|
||||||
|
$docker_compose['services'][$container_name]['logging'] = [
|
||||||
|
'driver' => 'fluentd',
|
||||||
|
'options' => [
|
||||||
|
'fluentd-address' => "tcp://127.0.0.1:24224",
|
||||||
|
'fluentd-async' => "true",
|
||||||
|
'fluentd-sub-second-precision' => "true",
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
if (count($this->database->ports_mappings_array) > 0) {
|
if (count($this->database->ports_mappings_array) > 0) {
|
||||||
$docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
|
$docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,16 @@ public function handle(StandaloneMysql $database)
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
if ($this->database->destination->server->isDrainLogActivated()) {
|
||||||
|
$docker_compose['services'][$container_name]['logging'] = [
|
||||||
|
'driver' => 'fluentd',
|
||||||
|
'options' => [
|
||||||
|
'fluentd-address' => "tcp://127.0.0.1:24224",
|
||||||
|
'fluentd-async' => "true",
|
||||||
|
'fluentd-sub-second-precision' => "true",
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
if (count($this->database->ports_mappings_array) > 0) {
|
if (count($this->database->ports_mappings_array) > 0) {
|
||||||
$docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
|
$docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,16 @@ public function handle(StandalonePostgresql $database)
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
if ($this->database->destination->server->isDrainLogActivated()) {
|
||||||
|
$docker_compose['services'][$container_name]['logging'] = [
|
||||||
|
'driver' => 'fluentd',
|
||||||
|
'options' => [
|
||||||
|
'fluentd-address' => "tcp://127.0.0.1:24224",
|
||||||
|
'fluentd-async' => "true",
|
||||||
|
'fluentd-sub-second-precision' => "true",
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
if (count($this->database->ports_mappings_array) > 0) {
|
if (count($this->database->ports_mappings_array) > 0) {
|
||||||
$docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
|
$docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,16 @@ public function handle(StandaloneRedis $database)
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
if ($this->database->destination->server->isDrainLogActivated()) {
|
||||||
|
$docker_compose['services'][$container_name]['logging'] = [
|
||||||
|
'driver' => 'fluentd',
|
||||||
|
'options' => [
|
||||||
|
'fluentd-address' => "tcp://127.0.0.1:24224",
|
||||||
|
'fluentd-async' => "true",
|
||||||
|
'fluentd-sub-second-precision' => "true",
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
if (count($this->database->ports_mappings_array) > 0) {
|
if (count($this->database->ports_mappings_array) > 0) {
|
||||||
$docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
|
$docker_compose['services'][$container_name]['ports'] = $this->database->ports_mappings_array;
|
||||||
}
|
}
|
||||||
|
185
app/Actions/Server/InstallLogDrain.php
Normal file
185
app/Actions/Server/InstallLogDrain.php
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Actions\Server;
|
||||||
|
|
||||||
|
use Lorisleiva\Actions\Concerns\AsAction;
|
||||||
|
use App\Models\Server;
|
||||||
|
|
||||||
|
class InstallLogDrain
|
||||||
|
{
|
||||||
|
use AsAction;
|
||||||
|
public function handle(Server $server, string $type)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if ($type === 'none') {
|
||||||
|
$command = [
|
||||||
|
"echo 'Stopping old Fluent Bit'",
|
||||||
|
"docker rm -f coolify-log-drain || true",
|
||||||
|
];
|
||||||
|
return instant_remote_process($command, $server);
|
||||||
|
} else if ($type === 'newrelic') {
|
||||||
|
if (!$server->settings->is_logdrain_newrelic_enabled) {
|
||||||
|
throw new \Exception('New Relic log drain is not enabled.');
|
||||||
|
}
|
||||||
|
$config = base64_encode("
|
||||||
|
[SERVICE]
|
||||||
|
Flush 5
|
||||||
|
Daemon off
|
||||||
|
Tag container_logs
|
||||||
|
Log_Level debug
|
||||||
|
Parsers_File parsers.conf
|
||||||
|
[INPUT]
|
||||||
|
Name forward
|
||||||
|
Buffer_Chunk_Size 1M
|
||||||
|
Buffer_Max_Size 6M
|
||||||
|
[FILTER]
|
||||||
|
Name grep
|
||||||
|
Match *
|
||||||
|
Exclude log 127.0.0.1
|
||||||
|
[FILTER]
|
||||||
|
Name modify
|
||||||
|
Match *
|
||||||
|
Set server_name {$server->name}
|
||||||
|
[OUTPUT]
|
||||||
|
Name nrlogs
|
||||||
|
Match *
|
||||||
|
license_key \${LICENSE_KEY}
|
||||||
|
# https://log-api.eu.newrelic.com/log/v1 - EU
|
||||||
|
# https://log-api.newrelic.com/log/v1 - US
|
||||||
|
base_uri \${BASE_URI}
|
||||||
|
");
|
||||||
|
} else if ($type === 'highlight') {
|
||||||
|
if (!$server->settings->is_logdrain_highlight_enabled) {
|
||||||
|
throw new \Exception('Highlight log drain is not enabled.');
|
||||||
|
}
|
||||||
|
$config = base64_encode("
|
||||||
|
[SERVICE]
|
||||||
|
Flush 5
|
||||||
|
Daemon off
|
||||||
|
Log_Level debug
|
||||||
|
Parsers_File parsers.conf
|
||||||
|
[INPUT]
|
||||||
|
Name forward
|
||||||
|
tag \${HIGHLIGHT_PROJECT_ID}
|
||||||
|
Buffer_Chunk_Size 1M
|
||||||
|
Buffer_Max_Size 6M
|
||||||
|
[OUTPUT]
|
||||||
|
Name forward
|
||||||
|
Match *
|
||||||
|
Host otel.highlight.io
|
||||||
|
Port 24224
|
||||||
|
");
|
||||||
|
} else if ($type === 'axiom') {
|
||||||
|
if (!$server->settings->is_logdrain_axiom_enabled) {
|
||||||
|
throw new \Exception('Axiom log drain is not enabled.');
|
||||||
|
}
|
||||||
|
$config = base64_encode("
|
||||||
|
[SERVICE]
|
||||||
|
Flush 5
|
||||||
|
Daemon off
|
||||||
|
Log_Level debug
|
||||||
|
Parsers_File parsers.conf
|
||||||
|
[INPUT]
|
||||||
|
Name forward
|
||||||
|
Buffer_Chunk_Size 1M
|
||||||
|
Buffer_Max_Size 6M
|
||||||
|
[FILTER]
|
||||||
|
Name grep
|
||||||
|
Match *
|
||||||
|
Exclude log 127.0.0.1
|
||||||
|
[FILTER]
|
||||||
|
Name modify
|
||||||
|
Match *
|
||||||
|
Set server_name {$server->name}
|
||||||
|
[OUTPUT]
|
||||||
|
Name http
|
||||||
|
Match *
|
||||||
|
Host api.axiom.co
|
||||||
|
Port 443
|
||||||
|
URI /v1/datasets/\${AXIOM_DATASET_NAME}/ingest
|
||||||
|
# Authorization Bearer should be an API token
|
||||||
|
Header Authorization Bearer \${AXIOM_API_KEY}
|
||||||
|
compress gzip
|
||||||
|
format json
|
||||||
|
json_date_key _time
|
||||||
|
json_date_format iso8601
|
||||||
|
tls On
|
||||||
|
");
|
||||||
|
} else {
|
||||||
|
throw new \Exception('Unknown log drain type.');
|
||||||
|
}
|
||||||
|
$parsers = base64_encode("
|
||||||
|
[PARSER]
|
||||||
|
Name empty_line_skipper
|
||||||
|
Format regex
|
||||||
|
Regex /^(?!\s*$).+/
|
||||||
|
");
|
||||||
|
$compose = base64_encode("
|
||||||
|
services:
|
||||||
|
coolify-log-drain:
|
||||||
|
image: cr.fluentbit.io/fluent/fluent-bit:2.0
|
||||||
|
container_name: coolify-log-drain
|
||||||
|
command: -c /fluent-bit.conf
|
||||||
|
env_file:
|
||||||
|
- .env
|
||||||
|
volumes:
|
||||||
|
- ./fluent-bit.conf:/fluent-bit.conf
|
||||||
|
- ./parsers.conf:/parsers.conf
|
||||||
|
ports:
|
||||||
|
- 127.0.0.1:24224:24224
|
||||||
|
");
|
||||||
|
$readme = base64_encode('# New Relic Log Drain
|
||||||
|
This log drain is based on [Fluent Bit](https://fluentbit.io/) and New Relic Log Forwarder.
|
||||||
|
|
||||||
|
Files:
|
||||||
|
- `fluent-bit.conf` - configuration file for Fluent Bit
|
||||||
|
- `docker-compose.yml` - docker-compose file to run Fluent Bit
|
||||||
|
- `.env` - environment variables for Fluent Bit
|
||||||
|
');
|
||||||
|
$license_key = $server->settings->logdrain_newrelic_license_key;
|
||||||
|
$base_uri = $server->settings->logdrain_newrelic_base_uri;
|
||||||
|
$base_path = config('coolify.base_config_path');
|
||||||
|
|
||||||
|
$config_path = $base_path . '/log-drains';
|
||||||
|
$fluent_bit_config = $config_path . '/fluent-bit.conf';
|
||||||
|
$parsers_config = $config_path . '/parsers.conf';
|
||||||
|
$compose_path = $config_path . '/docker-compose.yml';
|
||||||
|
$readme_path = $config_path . '/README.md';
|
||||||
|
$command = [
|
||||||
|
"echo 'Saving configuration'",
|
||||||
|
"mkdir -p $config_path",
|
||||||
|
"echo '{$parsers}' | base64 -d > $parsers_config",
|
||||||
|
"echo '{$config}' | base64 -d > $fluent_bit_config",
|
||||||
|
"echo '{$compose}' | base64 -d > $compose_path",
|
||||||
|
"echo '{$readme}' | base64 -d > $readme_path",
|
||||||
|
"test -f $config_path/.env && rm $config_path/.env",
|
||||||
|
|
||||||
|
];
|
||||||
|
if ($type === 'newrelic') {
|
||||||
|
$add_envs_command = [
|
||||||
|
"echo LICENSE_KEY=$license_key >> $config_path/.env",
|
||||||
|
"echo BASE_URI=$base_uri >> $config_path/.env",
|
||||||
|
];
|
||||||
|
} else if ($type === 'highlight') {
|
||||||
|
$add_envs_command = [
|
||||||
|
"echo HIGHLIGHT_PROJECT_ID={$server->settings->logdrain_highlight_project_id} >> $config_path/.env",
|
||||||
|
];
|
||||||
|
} else if ($type === 'axiom') {
|
||||||
|
$add_envs_command = [
|
||||||
|
"echo AXIOM_DATASET_NAME={$server->settings->logdrain_axiom_dataset_name} >> $config_path/.env",
|
||||||
|
"echo AXIOM_API_KEY={$server->settings->logdrain_axiom_api_key} >> $config_path/.env",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
$restart_command = [
|
||||||
|
"echo 'Stopping old Fluent Bit'",
|
||||||
|
"cd $config_path && docker rm -f coolify-log-drain || true",
|
||||||
|
"echo 'Starting Fluent Bit'",
|
||||||
|
"cd $config_path && docker compose up -d --remove-orphans",
|
||||||
|
];
|
||||||
|
$command = array_merge($command, $add_envs_command, $restart_command);
|
||||||
|
return instant_remote_process($command, $server);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,9 +3,11 @@
|
|||||||
namespace App\Console\Commands;
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
use App\Enums\ApplicationDeploymentStatus;
|
use App\Enums\ApplicationDeploymentStatus;
|
||||||
|
use App\Jobs\CleanupHelperContainersJob;
|
||||||
use App\Models\Application;
|
use App\Models\Application;
|
||||||
use App\Models\ApplicationDeploymentQueue;
|
use App\Models\ApplicationDeploymentQueue;
|
||||||
use App\Models\InstanceSettings;
|
use App\Models\InstanceSettings;
|
||||||
|
use App\Models\Server;
|
||||||
use App\Models\Service;
|
use App\Models\Service;
|
||||||
use App\Models\ServiceApplication;
|
use App\Models\ServiceApplication;
|
||||||
use App\Models\ServiceDatabase;
|
use App\Models\ServiceDatabase;
|
||||||
@ -32,6 +34,16 @@ public function handle()
|
|||||||
$this->cleanup_ssh();
|
$this->cleanup_ssh();
|
||||||
}
|
}
|
||||||
$this->cleanup_in_progress_application_deployments();
|
$this->cleanup_in_progress_application_deployments();
|
||||||
|
$this->cleanup_stucked_helper_containers();
|
||||||
|
}
|
||||||
|
private function cleanup_stucked_helper_containers() {
|
||||||
|
$servers = Server::all();
|
||||||
|
foreach ($servers as $server) {
|
||||||
|
if ($server->isFunctional()) {
|
||||||
|
CleanupHelperContainersJob::dispatch($server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
private function alive()
|
private function alive()
|
||||||
{
|
{
|
||||||
|
138
app/Http/Livewire/Server/LogDrains.php
Normal file
138
app/Http/Livewire/Server/LogDrains.php
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Livewire\Server;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Livewire\Component;
|
||||||
|
|
||||||
|
class LogDrains extends Component
|
||||||
|
{
|
||||||
|
public Server $server;
|
||||||
|
public $parameters = [];
|
||||||
|
protected $rules = [
|
||||||
|
'server.settings.is_logdrain_newrelic_enabled' => 'required|boolean',
|
||||||
|
'server.settings.logdrain_newrelic_license_key' => 'required|string',
|
||||||
|
'server.settings.logdrain_newrelic_base_uri' => 'required|string',
|
||||||
|
'server.settings.is_logdrain_highlight_enabled' => 'required|boolean',
|
||||||
|
'server.settings.logdrain_highlight_project_id' => 'required|string',
|
||||||
|
'server.settings.is_logdrain_axiom_enabled' => 'required|boolean',
|
||||||
|
'server.settings.logdrain_axiom_dataset_name' => 'required|string',
|
||||||
|
'server.settings.logdrain_axiom_api_key' => 'required|string',
|
||||||
|
];
|
||||||
|
protected $validationAttributes = [
|
||||||
|
'server.settings.is_logdrain_newrelic_enabled' => 'New Relic log drain',
|
||||||
|
'server.settings.logdrain_newrelic_license_key' => 'New Relic license key',
|
||||||
|
'server.settings.logdrain_newrelic_base_uri' => 'New Relic base URI',
|
||||||
|
'server.settings.is_logdrain_highlight_enabled' => 'Highlight log drain',
|
||||||
|
'server.settings.logdrain_highlight_project_id' => 'Highlight project ID',
|
||||||
|
'server.settings.is_logdrain_axiom_enabled' => 'Axiom log drain',
|
||||||
|
'server.settings.logdrain_axiom_dataset_name' => 'Axiom dataset name',
|
||||||
|
'server.settings.logdrain_axiom_api_key' => 'Axiom API key',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function mount()
|
||||||
|
{
|
||||||
|
$this->parameters = get_route_parameters();
|
||||||
|
try {
|
||||||
|
$server = Server::ownedByCurrentTeam(['name', 'description', 'ip', 'port', 'user', 'proxy'])->whereUuid(request()->server_uuid)->first();
|
||||||
|
if (is_null($server)) {
|
||||||
|
return redirect()->route('server.all');
|
||||||
|
}
|
||||||
|
$this->server = $server;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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');
|
||||||
|
$this->emit('serverRefresh');
|
||||||
|
$this->emit('success', 'Log drain service stopped.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->emit('serverRefresh');
|
||||||
|
$this->emit('success', 'Log drain service started successfully.');
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function instantSave(string $type)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$ok = $this->submit($type);
|
||||||
|
if (!$ok) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->configureLogDrain();
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return handleError($e, $this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function submit(string $type)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$this->resetErrorBag();
|
||||||
|
if ($type === 'newrelic') {
|
||||||
|
$this->validate([
|
||||||
|
'server.settings.is_logdrain_newrelic_enabled' => 'required|boolean',
|
||||||
|
'server.settings.logdrain_newrelic_license_key' => 'required|string',
|
||||||
|
'server.settings.logdrain_newrelic_base_uri' => 'required|string',
|
||||||
|
]);
|
||||||
|
$this->server->settings->update([
|
||||||
|
'is_logdrain_highlight_enabled' => false,
|
||||||
|
'is_logdrain_axiom_enabled' => false,
|
||||||
|
]);
|
||||||
|
} else if ($type === 'highlight') {
|
||||||
|
$this->validate([
|
||||||
|
'server.settings.is_logdrain_highlight_enabled' => 'required|boolean',
|
||||||
|
'server.settings.logdrain_highlight_project_id' => 'required|string',
|
||||||
|
]);
|
||||||
|
$this->server->settings->update([
|
||||||
|
'is_logdrain_newrelic_enabled' => false,
|
||||||
|
'is_logdrain_axiom_enabled' => false,
|
||||||
|
]);
|
||||||
|
} else if ($type === 'axiom') {
|
||||||
|
$this->validate([
|
||||||
|
'server.settings.is_logdrain_axiom_enabled' => 'required|boolean',
|
||||||
|
'server.settings.logdrain_axiom_dataset_name' => 'required|string',
|
||||||
|
'server.settings.logdrain_axiom_api_key' => 'required|string',
|
||||||
|
]);
|
||||||
|
$this->server->settings->update([
|
||||||
|
'is_logdrain_newrelic_enabled' => false,
|
||||||
|
'is_logdrain_highlight_enabled' => false,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
$this->server->settings->save();
|
||||||
|
$this->emit('success', 'Settings saved successfully.');
|
||||||
|
return true;
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
if ($type === 'newrelic') {
|
||||||
|
$this->server->settings->update([
|
||||||
|
'is_logdrain_newrelic_enabled' => false,
|
||||||
|
]);
|
||||||
|
} else if ($type === 'highlight') {
|
||||||
|
$this->server->settings->update([
|
||||||
|
'is_logdrain_highlight_enabled' => false,
|
||||||
|
]);
|
||||||
|
} else if ($type === 'axiom') {
|
||||||
|
$this->server->settings->update([
|
||||||
|
'is_logdrain_axiom_enabled' => false,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
handleError($e, $this);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public function render()
|
||||||
|
{
|
||||||
|
return view('livewire.server.log-drains');
|
||||||
|
}
|
||||||
|
}
|
@ -498,7 +498,7 @@ private function health_check()
|
|||||||
if ($this->full_healthcheck_url) {
|
if ($this->full_healthcheck_url) {
|
||||||
$this->execute_remote_command(
|
$this->execute_remote_command(
|
||||||
[
|
[
|
||||||
"echo 'Healthcheck URL inside your container: {$this->full_healthcheck_url}'"
|
"echo 'Healthcheck URL (inside the container): {$this->full_healthcheck_url}'"
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -837,13 +837,6 @@ private function generate_compose_file()
|
|||||||
'networks' => [
|
'networks' => [
|
||||||
$this->destination->network,
|
$this->destination->network,
|
||||||
],
|
],
|
||||||
// 'logging' => [
|
|
||||||
// 'driver' => 'fluentd',
|
|
||||||
// 'options' => [
|
|
||||||
// 'fluentd-async' => 'true',
|
|
||||||
// 'tag' => $this->application->name . '-' . $this->application->uuid
|
|
||||||
// ]
|
|
||||||
// ],
|
|
||||||
'healthcheck' => [
|
'healthcheck' => [
|
||||||
'test' => [
|
'test' => [
|
||||||
'CMD-SHELL',
|
'CMD-SHELL',
|
||||||
@ -871,6 +864,16 @@ private function generate_compose_file()
|
|||||||
]
|
]
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
if ($this->server->isDrainLogActivated()) {
|
||||||
|
$docker_compose['services'][$this->container_name]['logging'] = [
|
||||||
|
'driver' => 'fluentd',
|
||||||
|
'options' => [
|
||||||
|
'fluentd-address' => "tcp://127.0.0.1:24224",
|
||||||
|
'fluentd-async' => "true",
|
||||||
|
'fluentd-sub-second-precision' => "true",
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
if ($this->application->isHealthcheckDisabled()) {
|
if ($this->application->isHealthcheckDisabled()) {
|
||||||
data_forget($docker_compose, 'services.' . $this->container_name . '.healthcheck');
|
data_forget($docker_compose, 'services.' . $this->container_name . '.healthcheck');
|
||||||
}
|
}
|
||||||
@ -1019,6 +1022,10 @@ private function build_image()
|
|||||||
listen [::]:80;
|
listen [::]:80;
|
||||||
server_name localhost;
|
server_name localhost;
|
||||||
|
|
||||||
|
// real_ip_header X-Forwarded-For;
|
||||||
|
// proxy_set_header X-Real-IP \$remote_addr;
|
||||||
|
// proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
40
app/Jobs/CleanupHelperContainersJob.php
Normal file
40
app/Jobs/CleanupHelperContainersJob.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Jobs;
|
||||||
|
|
||||||
|
use App\Models\Server;
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeEncrypted;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class CleanupHelperContainersJob implements ShouldQueue, ShouldBeUnique, ShouldBeEncrypted
|
||||||
|
{
|
||||||
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||||
|
|
||||||
|
public function __construct(public Server $server)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(): void
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
ray('Cleaning up helper containers on ' . $this->server->name);
|
||||||
|
$containers = instant_remote_process(['docker container ps --filter "ancestor=ghcr.io/coollabsio/coolify-helper:next" --filter "ancestor=ghcr.io/coollabsio/coolify-helper:latest" --format \'{{json .}}\''], $this->server, false);
|
||||||
|
$containers = format_docker_command_output_to_json($containers);
|
||||||
|
if ($containers->count() > 0) {
|
||||||
|
foreach ($containers as $container) {
|
||||||
|
$containerId = data_get($container,'ID');
|
||||||
|
ray('Removing container ' . $containerId);
|
||||||
|
instant_remote_process(['docker container rm -f ' . $containerId], $this->server, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
send_internal_notification('CleanupHelperContainersJob failed with error: ' . $e->getMessage());
|
||||||
|
ray($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Actions\Server\InstallLogDrain;
|
||||||
|
use App\Actions\Server\InstallNewRelic;
|
||||||
use App\Enums\ProxyStatus;
|
use App\Enums\ProxyStatus;
|
||||||
use App\Enums\ProxyTypes;
|
use App\Enums\ProxyTypes;
|
||||||
use App\Notifications\Server\Revived;
|
use App\Notifications\Server\Revived;
|
||||||
@ -59,6 +61,8 @@ protected static function booted()
|
|||||||
|
|
||||||
public $casts = [
|
public $casts = [
|
||||||
'proxy' => SchemalessAttributes::class,
|
'proxy' => SchemalessAttributes::class,
|
||||||
|
'logdrain_axiom_api_key' => 'encrypted',
|
||||||
|
'logdrain_newrelic_license_key' => 'encrypted',
|
||||||
];
|
];
|
||||||
protected $schemalessAttributes = [
|
protected $schemalessAttributes = [
|
||||||
'proxy',
|
'proxy',
|
||||||
@ -296,10 +300,17 @@ public function isProxyShouldRun()
|
|||||||
// }
|
// }
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
public function logDrain($type)
|
||||||
|
{
|
||||||
|
InstallLogDrain::run($this, $type);
|
||||||
|
}
|
||||||
public function isFunctional()
|
public function isFunctional()
|
||||||
{
|
{
|
||||||
return $this->settings->is_reachable && $this->settings->is_usable;
|
return $this->settings->is_reachable && $this->settings->is_usable;
|
||||||
}
|
}
|
||||||
|
public function isDrainLogActivated() {
|
||||||
|
return $this->settings->is_logdrain_newrelic_enabled || $this->settings->is_logdrain_highlight_enabled || $this->settings->is_logdrain_axiom_enabled;
|
||||||
|
}
|
||||||
public function validateConnection()
|
public function validateConnection()
|
||||||
{
|
{
|
||||||
$uptime = instant_remote_process(['uptime'], $this, false);
|
$uptime = instant_remote_process(['uptime'], $this, false);
|
||||||
|
@ -797,6 +797,16 @@ public function parse(bool $isNew = false): Collection
|
|||||||
$serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($this->uuid, $fqdns, true));
|
$serviceLabels = $serviceLabels->merge(fqdnLabelsForTraefik($this->uuid, $fqdns, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ($this->server->isDrainLogActivated()) {
|
||||||
|
data_set($service, 'logging', [
|
||||||
|
'driver' => 'fluentd',
|
||||||
|
'options' => [
|
||||||
|
'fluentd-address' => "tcp://127.0.0.1:24224",
|
||||||
|
'fluentd-async' => "true",
|
||||||
|
'fluentd-sub-second-precision' => "true",
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
data_set($service, 'labels', $serviceLabels->toArray());
|
data_set($service, 'labels', $serviceLabels->toArray());
|
||||||
data_forget($service, 'is_database');
|
data_forget($service, 'is_database');
|
||||||
data_set($service, 'restart', RESTART_MODE);
|
data_set($service, 'restart', RESTART_MODE);
|
||||||
|
@ -10,7 +10,6 @@
|
|||||||
|
|
||||||
function getCurrentApplicationContainerStatus(Server $server, int $id, ?int $pullRequestId = null): Collection
|
function getCurrentApplicationContainerStatus(Server $server, int $id, ?int $pullRequestId = null): Collection
|
||||||
{
|
{
|
||||||
ray($id, $pullRequestId);
|
|
||||||
$containers = collect([]);
|
$containers = collect([]);
|
||||||
$containers = instant_remote_process(["docker ps -a --filter='label=coolify.applicationId={$id}' --format '{{json .}}' "], $server);
|
$containers = instant_remote_process(["docker ps -a --filter='label=coolify.applicationId={$id}' --format '{{json .}}' "], $server);
|
||||||
$containers = format_docker_command_output_to_json($containers);
|
$containers = format_docker_command_output_to_json($containers);
|
||||||
@ -26,7 +25,6 @@ function getCurrentApplicationContainerStatus(Server $server, int $id, ?int $pul
|
|||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
$containers = $containers->filter();
|
$containers = $containers->filter();
|
||||||
ray($containers);
|
|
||||||
return $containers;
|
return $containers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
// The release version of your application
|
// The release version of your application
|
||||||
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
// Example with dynamic git hash: trim(exec('git --git-dir ' . base_path('.git') . ' log --pretty="%h" -n1 HEAD'))
|
||||||
'release' => '4.0.0-beta.138',
|
'release' => '4.0.0-beta.139',
|
||||||
// When left empty or `null` the Laravel environment will be used
|
// When left empty or `null` the Laravel environment will be used
|
||||||
'environment' => config('app.env'),
|
'environment' => config('app.env'),
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
return '4.0.0-beta.138';
|
return '4.0.0-beta.139';
|
||||||
|
47
database/migrations/2023_11_16_220647_add_log_drains.php
Normal file
47
database/migrations/2023_11_16_220647_add_log_drains.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?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('server_settings', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_logdrain_newrelic_enabled')->default(false);
|
||||||
|
$table->string('logdrain_newrelic_license_key')->nullable();
|
||||||
|
$table->string('logdrain_newrelic_base_uri')->nullable();
|
||||||
|
|
||||||
|
$table->boolean('is_logdrain_highlight_enabled')->default(false);
|
||||||
|
$table->string('logdrain_highlight_project_id')->nullable();
|
||||||
|
|
||||||
|
$table->boolean('is_logdrain_axiom_enabled')->default(false);
|
||||||
|
$table->string('logdrain_axiom_dataset_name')->nullable();
|
||||||
|
$table->string('logdrain_axiom_api_key')->nullable();
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('server_settings', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_logdrain_newrelic_enabled');
|
||||||
|
$table->dropColumn('logdrain_newrelic_license_key');
|
||||||
|
$table->dropColumn('logdrain_newrelic_base_uri');
|
||||||
|
|
||||||
|
$table->dropColumn('is_logdrain_highlight_enabled');
|
||||||
|
$table->dropColumn('logdrain_highlight_project_id');
|
||||||
|
|
||||||
|
$table->dropColumn('is_logdrain_axiom_enabled');
|
||||||
|
$table->dropColumn('logdrain_axiom_dataset_name');
|
||||||
|
$table->dropColumn('logdrain_axiom_api_key');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -1,16 +0,0 @@
|
|||||||
[SERVICE]
|
|
||||||
Flush 1
|
|
||||||
Daemon off
|
|
||||||
[INPUT]
|
|
||||||
Name forward
|
|
||||||
Buffer_Chunk_Size 1M
|
|
||||||
Buffer_Max_Size 6M
|
|
||||||
# [OUTPUT]
|
|
||||||
# Name nrlogs
|
|
||||||
# Match *
|
|
||||||
# license_key ${LICENSE_KEY}
|
|
||||||
# base_uri https://log-api.eu.newrelic.com/log/v1
|
|
||||||
|
|
||||||
[OUTPUT]
|
|
||||||
Name stdout
|
|
||||||
Match *
|
|
@ -1,9 +0,0 @@
|
|||||||
version: '3'
|
|
||||||
services:
|
|
||||||
coolify-fluent-bit:
|
|
||||||
image: cr.fluentbit.io/fluent/fluent-bit:2.0
|
|
||||||
command: -c /fluent-bit.conf
|
|
||||||
volumes:
|
|
||||||
- ./fluent-bit.conf:/fluent-bit.conf
|
|
||||||
ports:
|
|
||||||
- 24224:24224
|
|
@ -1,21 +0,0 @@
|
|||||||
version: '3'
|
|
||||||
services:
|
|
||||||
newrelic-infra:
|
|
||||||
container_name: newrelic-infra
|
|
||||||
image: newrelic/infrastructure:latest
|
|
||||||
networks:
|
|
||||||
- coolify
|
|
||||||
cap_add:
|
|
||||||
- SYS_PTRACE
|
|
||||||
privileged: true
|
|
||||||
pid: host
|
|
||||||
volumes:
|
|
||||||
- "/:/host:ro"
|
|
||||||
- "/var/run/docker.sock:/var/run/docker.sock"
|
|
||||||
- "newrelic-infra:/etc/newrelic-infra"
|
|
||||||
environment:
|
|
||||||
- NRIA_LICENSE_KEY=${NRIA_LICENSE_KEY}
|
|
||||||
- NRIA_DISPLAY_NAME=${HOSTNAME}
|
|
||||||
|
|
||||||
networks:
|
|
||||||
coolify:
|
|
@ -1,34 +0,0 @@
|
|||||||
receivers:
|
|
||||||
hostmetrics:
|
|
||||||
collection_interval: 5s
|
|
||||||
scrapers:
|
|
||||||
cpu:
|
|
||||||
metrics:
|
|
||||||
system.cpu.utilization:
|
|
||||||
enabled: true
|
|
||||||
processors:
|
|
||||||
resourcedetection:
|
|
||||||
detectors: [env, system]
|
|
||||||
system:
|
|
||||||
hostname_sources: ["os"]
|
|
||||||
resource_attributes:
|
|
||||||
host.id:
|
|
||||||
enabled: true
|
|
||||||
batch:
|
|
||||||
memory_limiter:
|
|
||||||
check_interval: 1s
|
|
||||||
limit_mib: 1000
|
|
||||||
spike_limit_mib: 200
|
|
||||||
exporters:
|
|
||||||
debug:
|
|
||||||
verbosity: detailed
|
|
||||||
otlp:
|
|
||||||
endpoint: ${OTLP_ENDPOINT}
|
|
||||||
headers:
|
|
||||||
api-key: ${OTLP_API_KEY}
|
|
||||||
service:
|
|
||||||
pipelines:
|
|
||||||
metrics:
|
|
||||||
receivers: [hostmetrics]
|
|
||||||
processors: [memory_limiter, resourcedetection, batch]
|
|
||||||
exporters: [debug, otlp]
|
|
@ -32,6 +32,12 @@
|
|||||||
]) }}">
|
]) }}">
|
||||||
<button>Destinations</button>
|
<button>Destinations</button>
|
||||||
</a>
|
</a>
|
||||||
|
<a class="{{ request()->routeIs('server.log-drains') ? 'text-white' : '' }}"
|
||||||
|
href="{{ route('server.log-drains', [
|
||||||
|
'server_uuid' => data_get($parameters, 'server_uuid'),
|
||||||
|
]) }}">
|
||||||
|
<button>Log Drains</button>
|
||||||
|
</a>
|
||||||
<div class="flex-1"></div>
|
<div class="flex-1"></div>
|
||||||
<livewire:server.proxy.deploy :server="$server" />
|
<livewire:server.proxy.deploy :server="$server" />
|
||||||
</nav>
|
</nav>
|
||||||
|
66
resources/views/livewire/server/log-drains.blade.php
Normal file
66
resources/views/livewire/server/log-drains.blade.php
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<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="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">
|
||||||
|
<h3>New Relic</h3>
|
||||||
|
<div class="w-32">
|
||||||
|
<x-forms.checkbox instantSave='instantSave("newrelic")'
|
||||||
|
id="server.settings.is_logdrain_newrelic_enabled" label="Enabled" />
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
||||||
|
<x-forms.input type="password" required id="server.settings.logdrain_newrelic_license_key"
|
||||||
|
label="License Key" />
|
||||||
|
<x-forms.input required id="server.settings.logdrain_newrelic_base_uri"
|
||||||
|
placeholder="https://log-api.eu.newrelic.com/log/v1" label="Endpoint (EU / US)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end gap-4 pt-6">
|
||||||
|
<x-forms.button type="submit">
|
||||||
|
Save
|
||||||
|
</x-forms.button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
{{-- <h3>Highlight.io</h3>
|
||||||
|
<div class="w-32">
|
||||||
|
<x-forms.checkbox instantSave='instantSave("highlight")'
|
||||||
|
id="server.settings.is_logdrain_highlight_enabled" label="Enabled" />
|
||||||
|
</div>
|
||||||
|
<form wire:submit.prevent='submit("highlight")' class="flex flex-col">
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
||||||
|
<x-forms.input type="password" required id="server.settings.logdrain_highlight_project_id"
|
||||||
|
label="Project Id" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end gap-4 pt-6">
|
||||||
|
<x-forms.button type="submit">
|
||||||
|
Save
|
||||||
|
</x-forms.button>
|
||||||
|
</div>
|
||||||
|
</form> --}}
|
||||||
|
<h3>Axiom</h3>
|
||||||
|
<div class="w-32">
|
||||||
|
<x-forms.checkbox instantSave='instantSave("axiom")' id="server.settings.is_logdrain_axiom_enabled"
|
||||||
|
label="Enabled" />
|
||||||
|
</div>
|
||||||
|
<form wire:submit.prevent='submit("axiom")' class="flex flex-col">
|
||||||
|
<div class="flex flex-col gap-4">
|
||||||
|
<div class="flex flex-col w-full gap-2 xl:flex-row">
|
||||||
|
<x-forms.input type="password" required id="server.settings.logdrain_axiom_api_key"
|
||||||
|
label="API Key" />
|
||||||
|
<x-forms.input required id="server.settings.logdrain_axiom_dataset_name" label="Dataset Name" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-end gap-4 pt-6">
|
||||||
|
<x-forms.button type="submit">
|
||||||
|
Save
|
||||||
|
</x-forms.button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -16,6 +16,7 @@
|
|||||||
use App\Http\Livewire\Server\All;
|
use App\Http\Livewire\Server\All;
|
||||||
use App\Http\Livewire\Server\Create;
|
use App\Http\Livewire\Server\Create;
|
||||||
use App\Http\Livewire\Server\Destination\Show as DestinationShow;
|
use App\Http\Livewire\Server\Destination\Show as DestinationShow;
|
||||||
|
use App\Http\Livewire\Server\LogDrains;
|
||||||
use App\Http\Livewire\Server\PrivateKey\Show as PrivateKeyShow;
|
use App\Http\Livewire\Server\PrivateKey\Show as PrivateKeyShow;
|
||||||
use App\Http\Livewire\Server\Proxy\Show as ProxyShow;
|
use App\Http\Livewire\Server\Proxy\Show as ProxyShow;
|
||||||
use App\Http\Livewire\Server\Proxy\Logs as ProxyLogs;
|
use App\Http\Livewire\Server\Proxy\Logs as ProxyLogs;
|
||||||
@ -130,6 +131,7 @@
|
|||||||
Route::get('/server/{server_uuid}/proxy/logs', ProxyLogs::class)->name('server.proxy.logs');
|
Route::get('/server/{server_uuid}/proxy/logs', ProxyLogs::class)->name('server.proxy.logs');
|
||||||
Route::get('/server/{server_uuid}/private-key', PrivateKeyShow::class)->name('server.private-key');
|
Route::get('/server/{server_uuid}/private-key', PrivateKeyShow::class)->name('server.private-key');
|
||||||
Route::get('/server/{server_uuid}/destinations', DestinationShow::class)->name('server.destinations');
|
Route::get('/server/{server_uuid}/destinations', DestinationShow::class)->name('server.destinations');
|
||||||
|
Route::get('/server/{server_uuid}/log-drains', LogDrains::class)->name('server.log-drains');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"version": "3.12.36"
|
"version": "3.12.36"
|
||||||
},
|
},
|
||||||
"v4": {
|
"v4": {
|
||||||
"version": "4.0.0-beta.138"
|
"version": "4.0.0-beta.139"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user