Telemetry (#4564)
This commit is contained in:
parent
df9a7f71f9
commit
ee033d6d08
5 changed files with 255 additions and 2 deletions
34
app/Console/Commands/TelemetryCommand.php
Normal file
34
app/Console/Commands/TelemetryCommand.php
Normal file
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Symfony\Component\VarDumper\VarDumper;
|
||||
use Pterodactyl\Services\Telemetry\TelemetryCollectionService;
|
||||
|
||||
class TelemetryCommand extends Command
|
||||
{
|
||||
protected $description = 'Displays all the data that would be sent to the Pterodactyl Telemetry Service if telemetry collection is enabled.';
|
||||
|
||||
protected $signature = 'p:telemetry';
|
||||
|
||||
/**
|
||||
* TelemetryCommand constructor.
|
||||
*/
|
||||
public function __construct(private TelemetryCollectionService $telemetryCollectionService)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle execution of command.
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$this->output->info('Collecting telemetry data, this may take a while...');
|
||||
|
||||
VarDumper::dump($this->telemetryCollectionService->collect());
|
||||
}
|
||||
}
|
|
@ -2,10 +2,13 @@
|
|||
|
||||
namespace Pterodactyl\Console;
|
||||
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Pterodactyl\Models\ActivityLog;
|
||||
use Illuminate\Console\Scheduling\Schedule;
|
||||
use Illuminate\Database\Console\PruneCommand;
|
||||
use Pterodactyl\Repositories\Eloquent\SettingsRepository;
|
||||
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
|
||||
use Pterodactyl\Services\Telemetry\TelemetryCollectionService;
|
||||
use Pterodactyl\Console\Commands\Schedule\ProcessRunnableCommand;
|
||||
use Pterodactyl\Console\Commands\Maintenance\PruneOrphanedBackupsCommand;
|
||||
use Pterodactyl\Console\Commands\Maintenance\CleanServiceBackupFilesCommand;
|
||||
|
@ -37,5 +40,34 @@ class Kernel extends ConsoleKernel
|
|||
if (config('activity.prune_days')) {
|
||||
$schedule->command(PruneCommand::class, ['--model' => [ActivityLog::class]])->daily();
|
||||
}
|
||||
|
||||
if (config('pterodactyl.telemetry.enabled')) {
|
||||
$this->registerTelemetry($schedule);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* I wonder what this does.
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
* @throws \Illuminate\Contracts\Container\BindingResolutionException
|
||||
*/
|
||||
private function registerTelemetry(Schedule $schedule): void
|
||||
{
|
||||
$settingsRepository = app()->make(SettingsRepository::class);
|
||||
|
||||
$uuid = $settingsRepository->get('app:uuid');
|
||||
if (is_null($uuid)) {
|
||||
$uuid = Uuid::uuid4()->toString();
|
||||
$settingsRepository->set('app:uuid', $uuid);
|
||||
}
|
||||
|
||||
// Calculate a fixed time to run the data push at, this will be the same time every day.
|
||||
$time = hexdec(str_replace('-', '', substr($uuid, 27))) % 1440;
|
||||
$hour = floor($time / 60);
|
||||
$minute = $time % 60;
|
||||
|
||||
// Run the telemetry collector.
|
||||
$schedule->call(app()->make(TelemetryCollectionService::class))->description('Collect Telemetry')->dailyAt("$hour:$minute");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,10 +14,10 @@ class DaemonConfigurationRepository extends DaemonRepository
|
|||
*
|
||||
* @throws \Pterodactyl\Exceptions\Http\Connection\DaemonConnectionException
|
||||
*/
|
||||
public function getSystemInformation(): array
|
||||
public function getSystemInformation(?int $version = null): array
|
||||
{
|
||||
try {
|
||||
$response = $this->getHttpClient()->get('/api/system');
|
||||
$response = $this->getHttpClient()->get('/api/system' . (!is_null($version) ? '?v=' . $version : ''));
|
||||
} catch (TransferException $exception) {
|
||||
throw new DaemonConnectionException($exception);
|
||||
}
|
||||
|
|
175
app/Services/Telemetry/TelemetryCollectionService.php
Normal file
175
app/Services/Telemetry/TelemetryCollectionService.php
Normal file
|
@ -0,0 +1,175 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Services\Telemetry;
|
||||
|
||||
use PDO;
|
||||
use Exception;
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Illuminate\Support\Arr;
|
||||
use Pterodactyl\Models\Egg;
|
||||
use Pterodactyl\Models\Nest;
|
||||
use Pterodactyl\Models\Node;
|
||||
use Pterodactyl\Models\User;
|
||||
use Pterodactyl\Models\Mount;
|
||||
use Pterodactyl\Models\Backup;
|
||||
use Pterodactyl\Models\Server;
|
||||
use Pterodactyl\Models\Location;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Pterodactyl\Models\Allocation;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Pterodactyl\Repositories\Eloquent\SettingsRepository;
|
||||
use Pterodactyl\Repositories\Wings\DaemonConfigurationRepository;
|
||||
|
||||
class TelemetryCollectionService
|
||||
{
|
||||
/**
|
||||
* TelemetryCollectionService constructor.
|
||||
*/
|
||||
public function __construct(
|
||||
private DaemonConfigurationRepository $daemonConfigurationRepository,
|
||||
private SettingsRepository $settingsRepository
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects telemetry data and sends it to the Pterodactyl Telemetry Service.
|
||||
*/
|
||||
public function __invoke(): void
|
||||
{
|
||||
try {
|
||||
$data = $this->collect();
|
||||
} catch (Exception) {
|
||||
return;
|
||||
}
|
||||
|
||||
Http::post('https://telemetry.pterodactyl.io', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects telemetry data and returns it as an array.
|
||||
*
|
||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||
*/
|
||||
public function collect(): array
|
||||
{
|
||||
$uuid = $this->settingsRepository->get('app:uuid');
|
||||
if (is_null($uuid)) {
|
||||
$uuid = Uuid::uuid4()->toString();
|
||||
$this->settingsRepository->set('app:uuid', $uuid);
|
||||
}
|
||||
|
||||
$nodes = Node::all()->map(function ($node) {
|
||||
try {
|
||||
$info = $this->daemonConfigurationRepository->setNode($node)->getSystemInformation(2);
|
||||
} catch (Exception) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $node->uuid,
|
||||
'version' => Arr::get($info, 'version', ''),
|
||||
|
||||
'docker' => [
|
||||
'version' => Arr::get($info, 'docker.version', ''),
|
||||
|
||||
'cgroups' => [
|
||||
'driver' => Arr::get($info, 'docker.cgroups.driver', ''),
|
||||
'version' => Arr::get($info, 'docker.cgroups.version', ''),
|
||||
],
|
||||
|
||||
'containers' => [
|
||||
'total' => Arr::get($info, 'docker.containers.total', -1),
|
||||
'running' => Arr::get($info, 'docker.containers.running', -1),
|
||||
'paused' => Arr::get($info, 'docker.containers.paused', -1),
|
||||
'stopped' => Arr::get($info, 'docker.containers.stopped', -1),
|
||||
],
|
||||
|
||||
'storage' => [
|
||||
'driver' => Arr::get($info, 'docker.storage.driver', ''),
|
||||
'filesystem' => Arr::get($info, 'docker.storage.filesystem', ''),
|
||||
],
|
||||
|
||||
'runc' => [
|
||||
'version' => Arr::get($info, 'docker.runc.version', ''),
|
||||
],
|
||||
],
|
||||
|
||||
'system' => [
|
||||
'architecture' => Arr::get($info, 'system.architecture', ''),
|
||||
'cpuThreads' => Arr::get($info, 'system.cpu_threads', ''),
|
||||
'memoryBytes' => Arr::get($info, 'system.memory_bytes', ''),
|
||||
'kernelVersion' => Arr::get($info, 'system.kernel_version', ''),
|
||||
'os' => Arr::get($info, 'system.os', ''),
|
||||
'osType' => Arr::get($info, 'system.os_type', ''),
|
||||
],
|
||||
];
|
||||
})->filter(fn ($node) => !is_null($node))->toArray();
|
||||
|
||||
return [
|
||||
'id' => $uuid,
|
||||
|
||||
'panel' => [
|
||||
'version' => config('app.version'),
|
||||
'phpVersion' => phpversion(),
|
||||
|
||||
'drivers' => [
|
||||
'backup' => [
|
||||
'type' => config('backups.default'),
|
||||
],
|
||||
'cache' => [
|
||||
'type' => config('cache.default'),
|
||||
],
|
||||
'database' => [
|
||||
'type' => config('database.default'),
|
||||
'version' => DB::getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION),
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'resources' => [
|
||||
'allocations' => [
|
||||
'count' => Allocation::count(),
|
||||
'used' => Allocation::whereNotNull('server_id')->count(),
|
||||
],
|
||||
|
||||
'backups' => [
|
||||
'count' => Backup::count(),
|
||||
'bytes' => Backup::sum('bytes'),
|
||||
],
|
||||
|
||||
'eggs' => [
|
||||
'count' => Egg::count(),
|
||||
'ids' => Egg::pluck('uuid')->toArray(),
|
||||
],
|
||||
|
||||
'locations' => [
|
||||
'count' => Location::count(),
|
||||
],
|
||||
|
||||
'mounts' => [
|
||||
'count' => Mount::count(),
|
||||
],
|
||||
|
||||
'nests' => [
|
||||
'count' => Nest::count(),
|
||||
],
|
||||
|
||||
'nodes' => [
|
||||
'count' => Node::count(),
|
||||
],
|
||||
|
||||
'servers' => [
|
||||
'count' => Server::count(),
|
||||
'suspended' => Server::where('status', Server::STATUS_SUSPENDED)->count(),
|
||||
],
|
||||
|
||||
'users' => [
|
||||
'count' => User::count(),
|
||||
'admins' => User::where('root_admin', true)->count(),
|
||||
],
|
||||
],
|
||||
|
||||
'nodes' => $nodes,
|
||||
];
|
||||
}
|
||||
}
|
|
@ -177,4 +177,16 @@ return [
|
|||
// Should an email be sent to a server owner whenever their server is reinstalled?
|
||||
'send_reinstall_notification' => env('PTERODACTYL_SEND_REINSTALL_NOTIFICATION', true),
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Telemetry Settings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This section controls the telemetry sent by Pterodactyl.
|
||||
*/
|
||||
|
||||
'telemetry' => [
|
||||
'enabled' => env('PTERODACTYL_TELEMETRY_ENABLED', false),
|
||||
],
|
||||
];
|
||||
|
|
Loading…
Reference in a new issue