Compare commits

...
Author SHA1 Message Date
shimon d9ce61300d adjustments 2023-04-18 10:23:37 +03:00
shimon 4408b74dd3 adjustments 2023-04-17 20:16:52 +03:00
shimon c588b8ecc5 tests 2023-04-17 10:28:48 +03:00
shimon 6edc222cae tests 2023-04-17 10:28:00 +03:00
shimon c44bb27a35 usage migration 2023-03-19 15:06:01 +02:00
shimon 2377f168b1 usage migration 2023-03-16 14:52:48 +02:00
shimon 3e4ad615b9 usage migration 2023-03-14 20:19:43 +02:00
9 changed files with 655 additions and 54 deletions
+3 -1
View File
@@ -138,7 +138,9 @@ RUN chmod +x /usr/local/bin/doctor && \
chmod +x /usr/local/bin/worker-builds && \
chmod +x /usr/local/bin/worker-mails && \
chmod +x /usr/local/bin/worker-messaging && \
chmod +x /usr/local/bin/worker-webhooks
chmod +x /usr/local/bin/worker-webhooks && \
chmod +x /usr/local/bin/usage-create-metrics && \
chmod +x /usr/local/bin/usage-update-metrics
# Letsencrypt Permissions
RUN mkdir -p /etc/letsencrypt/live/ && chmod -Rf 755 /etc/letsencrypt/live/
+11
View File
@@ -3104,6 +3104,17 @@ $collections = [
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('metricV2'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 255,
'signed' => true,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
],
[
'$id' => ID::custom('region'),
'type' => Database::VAR_STRING,
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php usage-create-metrics $@
+3
View File
@@ -0,0 +1,3 @@
#!/bin/sh
php /usr/src/code/app/cli.php usage-update-metrics $@
Generated
+145 -51
View File
@@ -620,16 +620,16 @@
},
{
"name": "guzzlehttp/psr7",
"version": "2.4.3",
"version": "2.4.4",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "67c26b443f348a51926030c83481b85718457d3d"
"reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/67c26b443f348a51926030c83481b85718457d3d",
"reference": "67c26b443f348a51926030c83481b85718457d3d",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
"reference": "3cf1b6d4f0c820a2cf8bcaec39fc698f3443b5cf",
"shasum": ""
},
"require": {
@@ -719,7 +719,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.4.3"
"source": "https://github.com/guzzle/psr7/tree/2.4.4"
},
"funding": [
{
@@ -735,7 +735,7 @@
"type": "tidelift"
}
],
"time": "2022-10-26T14:07:24+00:00"
"time": "2023-03-09T13:19:02+00:00"
},
{
"name": "influxdb/influxdb-php",
@@ -872,34 +872,37 @@
},
{
"name": "league/csv",
"version": "9.8.0",
"version": "9.9.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/csv.git",
"reference": "9d2e0265c5d90f5dd601bc65ff717e05cec19b47"
"reference": "b4418ede47fbd88facc34e40a16c8ce9153b961b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/csv/zipball/9d2e0265c5d90f5dd601bc65ff717e05cec19b47",
"reference": "9d2e0265c5d90f5dd601bc65ff717e05cec19b47",
"url": "https://api.github.com/repos/thephpleague/csv/zipball/b4418ede47fbd88facc34e40a16c8ce9153b961b",
"reference": "b4418ede47fbd88facc34e40a16c8ce9153b961b",
"shasum": ""
},
"require": {
"ext-json": "*",
"ext-mbstring": "*",
"php": "^7.4 || ^8.0"
"php": "^8.1.2"
},
"require-dev": {
"ext-curl": "*",
"doctrine/collections": "^2.1.2",
"ext-dom": "*",
"friendsofphp/php-cs-fixer": "^v3.4.0",
"phpstan/phpstan": "^1.3.0",
"phpstan/phpstan-phpunit": "^1.0.0",
"phpstan/phpstan-strict-rules": "^1.1.0",
"phpunit/phpunit": "^9.5.11"
"ext-xdebug": "*",
"friendsofphp/php-cs-fixer": "^v3.14.3",
"phpbench/phpbench": "^1.2.8",
"phpstan/phpstan": "^1.10.4",
"phpstan/phpstan-deprecation-rules": "^1.1.2",
"phpstan/phpstan-phpunit": "^1.3.10",
"phpstan/phpstan-strict-rules": "^1.5.0",
"phpunit/phpunit": "^10.0.14"
},
"suggest": {
"ext-dom": "Required to use the XMLConverter and or the HTMLConverter classes",
"ext-dom": "Required to use the XMLConverter and the HTMLConverter classes",
"ext-iconv": "Needed to ease transcoding CSV using iconv stream filters"
},
"type": "library",
@@ -952,7 +955,7 @@
"type": "github"
}
],
"time": "2022-01-04T00:13:07+00:00"
"time": "2023-03-11T15:57:12+00:00"
},
{
"name": "matomo/device-detector",
@@ -1153,21 +1156,21 @@
},
{
"name": "psr/http-client",
"version": "1.0.1",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-client.git",
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
"reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
"url": "https://api.github.com/repos/php-fig/http-client/zipball/0955afe48220520692d2d09f7ab7e0f93ffd6a31",
"reference": "0955afe48220520692d2d09f7ab7e0f93ffd6a31",
"shasum": ""
},
"require": {
"php": "^7.0 || ^8.0",
"psr/http-message": "^1.0"
"psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
@@ -1187,7 +1190,7 @@
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for HTTP clients",
@@ -1199,27 +1202,27 @@
"psr-18"
],
"support": {
"source": "https://github.com/php-fig/http-client/tree/master"
"source": "https://github.com/php-fig/http-client/tree/1.0.2"
},
"time": "2020-06-29T06:28:15+00:00"
"time": "2023-04-10T20:12:12+00:00"
},
{
"name": "psr/http-factory",
"version": "1.0.1",
"version": "1.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-factory.git",
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
"reference": "e616d01114759c4c489f93b099585439f795fe35"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
"reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
"url": "https://api.github.com/repos/php-fig/http-factory/zipball/e616d01114759c4c489f93b099585439f795fe35",
"reference": "e616d01114759c4c489f93b099585439f795fe35",
"shasum": ""
},
"require": {
"php": ">=7.0.0",
"psr/http-message": "^1.0"
"psr/http-message": "^1.0 || ^2.0"
},
"type": "library",
"extra": {
@@ -1239,7 +1242,7 @@
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interfaces for PSR-7 HTTP message factories",
@@ -1254,31 +1257,31 @@
"response"
],
"support": {
"source": "https://github.com/php-fig/http-factory/tree/master"
"source": "https://github.com/php-fig/http-factory/tree/1.0.2"
},
"time": "2019-04-30T12:38:16+00:00"
"time": "2023-04-10T20:10:41+00:00"
},
{
"name": "psr/http-message",
"version": "1.0.1",
"version": "1.1",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
"reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
"php": "^7.2 || ^8.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
"dev-master": "1.1.x-dev"
}
},
"autoload": {
@@ -1307,9 +1310,9 @@
"response"
],
"support": {
"source": "https://github.com/php-fig/http-message/tree/master"
"source": "https://github.com/php-fig/http-message/tree/1.1"
},
"time": "2016-08-06T14:39:51+00:00"
"time": "2023-04-04T09:50:52+00:00"
},
{
"name": "psr/log",
@@ -2969,6 +2972,49 @@
},
"time": "2022-09-22T09:15:54+00:00"
},
{
"name": "doctrine/deprecations",
"version": "v1.0.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/deprecations.git",
"reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
"reference": "0e2a4f1f8cdfc7a92ec3b01c9334898c806b30de",
"shasum": ""
},
"require": {
"php": "^7.1|^8.0"
},
"require-dev": {
"doctrine/coding-standard": "^9",
"phpunit/phpunit": "^7.5|^8.5|^9.5",
"psr/log": "^1|^2|^3"
},
"suggest": {
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
},
"type": "library",
"autoload": {
"psr-4": {
"Doctrine\\Deprecations\\": "lib/Doctrine/Deprecations"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
"homepage": "https://www.doctrine-project.org/",
"support": {
"issues": "https://github.com/doctrine/deprecations/issues",
"source": "https://github.com/doctrine/deprecations/tree/v1.0.0"
},
"time": "2022-05-02T15:47:09+00:00"
},
{
"name": "doctrine/instantiator",
"version": "1.5.0",
@@ -3501,24 +3547,27 @@
},
{
"name": "phpdocumentor/type-resolver",
"version": "1.6.2",
"version": "1.7.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/TypeResolver.git",
"reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d"
"reference": "dfc078e8af9c99210337325ff5aa152872c98714"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/48f445a408c131e38cab1c235aa6d2bb7a0bb20d",
"reference": "48f445a408c131e38cab1c235aa6d2bb7a0bb20d",
"url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/dfc078e8af9c99210337325ff5aa152872c98714",
"reference": "dfc078e8af9c99210337325ff5aa152872c98714",
"shasum": ""
},
"require": {
"doctrine/deprecations": "^1.0",
"php": "^7.4 || ^8.0",
"phpdocumentor/reflection-common": "^2.0"
"phpdocumentor/reflection-common": "^2.0",
"phpstan/phpdoc-parser": "^1.13"
},
"require-dev": {
"ext-tokenizer": "*",
"phpbench/phpbench": "^1.2",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-phpunit": "^1.1",
@@ -3550,9 +3599,9 @@
"description": "A PSR-5 based resolver of Class names, Types and Structural Element Names",
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.2"
"source": "https://github.com/phpDocumentor/TypeResolver/tree/1.7.1"
},
"time": "2022-10-14T12:47:21+00:00"
"time": "2023-03-27T19:02:04+00:00"
},
{
"name": "phpspec/prophecy",
@@ -3622,6 +3671,51 @@
},
"time": "2023-02-02T15:41:36+00:00"
},
{
"name": "phpstan/phpdoc-parser",
"version": "1.18.1",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpdoc-parser.git",
"reference": "22dcdfd725ddf99583bfe398fc624ad6c5004a0f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/22dcdfd725ddf99583bfe398fc624ad6c5004a0f",
"reference": "22dcdfd725ddf99583bfe398fc624ad6c5004a0f",
"shasum": ""
},
"require": {
"php": "^7.2 || ^8.0"
},
"require-dev": {
"php-parallel-lint/php-parallel-lint": "^1.2",
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^1.5",
"phpstan/phpstan-phpunit": "^1.1",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^9.5",
"symfony/process": "^5.2"
},
"type": "library",
"autoload": {
"psr-4": {
"PHPStan\\PhpDocParser\\": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "PHPDoc parser with support for nullable, intersection and generic types",
"support": {
"issues": "https://github.com/phpstan/phpdoc-parser/issues",
"source": "https://github.com/phpstan/phpdoc-parser/tree/1.18.1"
},
"time": "2023-04-07T11:51:11+00:00"
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.26",
@@ -5473,5 +5567,5 @@
"platform-overrides": {
"php": "8.0"
},
"plugin-api-version": "2.3.0"
"plugin-api-version": "2.2.0"
}
+5 -1
View File
@@ -2,6 +2,8 @@
namespace Appwrite\Platform\Services;
use Appwrite\Platform\Tasks\UsageUpdateMetrics;
use Appwrite\Platform\Tasks\UsageCreateMetrics;
use Utopia\Platform\Service;
use Appwrite\Platform\Tasks\Doctor;
use Appwrite\Platform\Tasks\Install;
@@ -37,6 +39,8 @@ class Tasks extends Service
->addAction(Migrate::getName(), new Migrate())
->addAction(SDKs::getName(), new SDKs())
->addAction(VolumeSync::getName(), new VolumeSync())
->addAction(Specs::getName(), new Specs());
->addAction(Specs::getName(), new Specs())
->addAction(UsageUpdateMetrics::getName(), new UsageUpdateMetrics())
->addAction(UsageCreateMetrics::getName(), new UsageCreateMetrics());
}
}
@@ -0,0 +1,262 @@
<?php
namespace Appwrite\Platform\Tasks;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Platform\Action;
use Utopia\CLI\Console;
use Utopia\Database\Validator\Authorization;
/**
* 1. docker compose exec -t appwrite usage-update-metrics
* 2. docker compose exec -t appwrite usage-create-metrics
* 3. docker compose exec -t appwrite usage-update-metrics commit=true
** docker compose exec -t appwrite usage-update-metrics rollback=true (in case somthing went wrong)**
*/
class UsageCreateMetrics extends Action
{
public static function getName(): string
{
return 'usage-create-metrics';
}
public function __construct()
{
$this
->desc('Usage inf metric calculation')->inject('dbForConsole')
->inject('getProjectDB')
->callback(fn(Database $dbForConsole, callable $getProjectDB) => $this->action($dbForConsole, $getProjectDB));
}
/**
* @throws \Exception
*/
public function action(Database $dbForConsole, callable $getProjectDB): void
{
Authorization::disable();
Authorization::setDefaultStatus(false);
function createInfMetric($dbForProject, $key, $value): void
{
$id = \md5("null_inf_{$key}");
$stats = $dbForProject->getDocument('stats', $id);
if ($stats->isEmpty()) {
$stats = $dbForProject->createDocument('stats', new Document([
'$id' => $id,
'period' => 'inf',
'time' => null,
'metric' => '',
'metricV2' => $key,
'value' => (int)$value,
'region' => 'default',
]));
} else {
$stats->setAttribute('value', (int)($stats['value'] + $value));
$dbForProject->updateDocument('stats', $stats->getId(), $stats);
}
Console::log($stats->getId() . ', ' . $key . ', inf,' . $stats->getAttribute('value'));
}
$limit = 100;
$projectCursor = null;
while (true) {
$projectsQueries = [Query::limit($limit)];
if ($projectCursor !== null) {
$projectsQueries[] = Query::cursorAfter($projectCursor);
}
$projects = $dbForConsole->find('projects', $projectsQueries);
if (count($projects) === 0) {
Console::info("**** Could not found any projects ****");
break;
}
foreach ($projects as $project) {
Console::info(PHP_EOL . "Project " . $project->getAttribute('name') . " (" . $project->getInternalId() . ")");
/**
* Delete (reset) inf metric if exists (in case of multiple executions)
*/
$dbForProject = $getProjectDB($project);
$statsQueries[] = Query::equal('period', ['inf']);
$statsCursor = null;
while (true) {
$statsQueries = [Query::limit($limit)];
$statsQueries[] = Query::equal('period', ['inf']);
if ($statsCursor !== null) {
$statsQueries[] = Query::cursorAfter($statsCursor);
}
$stats = $dbForProject->find('stats', $statsQueries);
if (count($stats) === 0) {
Console::info("**** Could not found any stats to delete ****");
break;
}
foreach ($stats as $stat) {
$dbForProject->deleteDocument('stats', $stat->getId());
Console::error('deleting ' . $stat->getId() . ',' . $stat['metricV2'] . ',' . $stat['period']);
}
$statsCursor = $stats[array_key_last($stats)];
}
/**
* Network - inbound, outbound, requests
*/
$metrics = [];
$metrics[] = ['from' => 'project.$all.network.outbound', 'to' => 'network.outbound'];
$metrics[] = ['from' => 'project.$all.network.inbound', 'to' => 'network.inbound'];
$metrics[] = ['from' => 'project.$all.network.requests', 'to' => 'network.requests'];
foreach ($metrics as $metric) {
$stats = $dbForProject->find('stats', [
Query::equal('metric', [$metric['from']]),
Query::equal('period', ['1d']),
Query::greaterThan('value', 0)
]);
foreach ($stats as $stat) {
createInfMetric($dbForProject, $metric['to'], $stat['value']);
}
}
/**
* users
*/
$users = $dbForProject->count('users', [
Query::equal('status', [1]),
]);
createInfMetric($dbForProject, 'users', $users);
/**
* Sessions
*/
$sessions = $dbForProject->count('sessions', []);
createInfMetric($dbForProject, 'sessions', $sessions);
/**
* Buckets, Files
*/
$filesStoragePerProject = 0;
$filesCountPerProject = 0;
$bucketsCountPerProject = 0;
$buckets = $dbForProject->find('buckets', []);
foreach ($buckets as $bucket) {
$filesCount = 0;
$filesStorage = 0;
$files = $dbForProject->find('bucket_' . $bucket->getInternalId(), []);
foreach ($files as $file) {
$filesStorage += $file['sizeOriginal'];
$filesStoragePerProject += $file['sizeOriginal'];
$filesCount++;
$filesCountPerProject++;
}
createInfMetric($dbForProject, $bucket->getInternalId() . '.files.storage', $filesStorage);
createInfMetric($dbForProject, $bucket->getInternalId() . '.files', $filesCount);
$bucketsCountPerProject++;
}
createInfMetric($dbForProject, 'files.storage', $filesStoragePerProject);
createInfMetric($dbForProject, 'files', $filesCountPerProject);
createInfMetric($dbForProject, 'buckets', $bucketsCountPerProject);
/**
* Databases, collections, documents
*/
$databasesCountPerProject = 0;
$collectionsCountPerProject = 0;
$documentsCountPerProject = 0;
$databases = $dbForProject->find('databases', []);
foreach ($databases as $database) {
$databasesCountPerProject++;
$documentsCountPerDatabase = 0;
$collectionCountPerDatabase = 0;
$collections = $dbForProject->find('database_' . $database->getInternalId(), []);
foreach ($collections as $collection) {
$documentsCountPerCollection = 0;
$collectionsCountPerProject++;
$collectionCountPerDatabase++;
$documents = $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), []);
$documentsCountPerProject += $documents;
$documentsCountPerDatabase += $documents;
$documentsCountPerCollection += $documents;
createInfMetric($dbForProject, $database->getInternalId() . '.' . $collection->getInternalId() . '.documents', $documentsCountPerCollection);
}
createInfMetric($dbForProject, $database->getInternalId() . '.documents', $documentsCountPerDatabase);
}
createInfMetric($dbForProject, 'databases', $databasesCountPerProject);
createInfMetric($dbForProject, 'collections', $collectionsCountPerProject);
createInfMetric($dbForProject, 'documents', $documentsCountPerProject);
/**
* Functions, deployments, builds, executions
*/
$deploymentSizePerProject = 0;
$deploymentCountPerProject = 0;
$buildDurationPerProject = 0;
$buildCountPerProject = 0;
$executionCountPerProject = 0;
$executionDurationPerProject = 0 ;
$functions = $dbForProject->find('functions', []);
foreach ($functions as $function) {
$deploymentSize = 0;
$deploymentCount = 0;
$buildDuration = 0;
$executionDuration = 0;
$executionCount = 0;
$buildCount = 0;
$deployments = $dbForProject->find('deployments', [
Query::equal('resourceId', [$function->getId()]),
]);
foreach ($deployments as $deployment) {
$deploymentSize += $deployment['size'];
$deploymentSizePerProject += $deployment['size'];
$deploymentCount++;
$deploymentCountPerProject++;
$build = $dbForProject->findOne('builds', [
Query::equal('deploymentId', [$deployment->getId()]),
]);
if (!empty($build)) {
$buildDuration += $build['duration'];
$buildDurationPerProject += $build['duration'];
$buildCountPerProject++;
$buildCount++;
}
}
createInfMetric($dbForProject, $function->getInternalId() . '.builds', $buildCount);
createInfMetric($dbForProject, $function->getInternalId() . '.builds.compute', (int)($buildDuration * 1000));
createInfMetric($dbForProject, $function->getInternalId() . '.deployments', $deploymentCount);
createInfMetric($dbForProject, $function->getInternalId() . '.deployments.storage', $deploymentSize);
$executions = $dbForProject->find('executions', [
Query::equal('functionId', [$function->getId()])
]);
foreach ($executions as $execution) {
$executionDuration += $execution['duration'];
$executionDurationPerProject += $execution['duration'];
$executionCount++;
$executionCountPerProject++;
}
createInfMetric($dbForProject, $function->getInternalId() . '.executions.compute', (int)($executionDuration * 1000));
createInfMetric($dbForProject, $function->getInternalId() . '.executions', $executionCount);
}
createInfMetric($dbForProject, 'deployments', $deploymentCountPerProject);
createInfMetric($dbForProject, 'builds', $buildCountPerProject);
createInfMetric($dbForProject, 'executions', $executionCountPerProject);
createInfMetric($dbForProject, 'deployments.storage', $deploymentSizePerProject);
createInfMetric($dbForProject, 'builds.compute', (int)($buildDurationPerProject * 1000));
createInfMetric($dbForProject, 'executions.compute', (int)($executionDurationPerProject * 1000));
}
$projectCursor = $projects[array_key_last($projects)];
}
}
}
@@ -0,0 +1,222 @@
<?php
namespace Appwrite\Platform\Tasks;
use Utopia\Database\Database;
use Utopia\Database\Query;
use Utopia\Platform\Action;
use Utopia\CLI\Console;
use Utopia\Database\Validator\Authorization;
use Utopia\Validator\Boolean;
class UsageUpdateMetrics extends Action
{
public static function getName(): string
{
return 'usage-update-metrics';
}
public function __construct()
{
$this
->desc('Migrate old usage metric pattern to new')
->param('commit', false, new Boolean(true), 'Switch usage metric columns', true)
->param('rollback', false, new Boolean(true), 'Rollback usage metric columns ', true)
->inject('dbForConsole')
->inject('getProjectDB')
->callback(fn(bool $commit, $rollback, Database $dbForConsole, callable $getProjectDB) => $this->action($commit, $rollback, $dbForConsole, $getProjectDB));
}
public function action(bool $commit, $rollback, Database $dbForConsole, callable $getProjectDB): void
{
Authorization::disable();
Authorization::setDefaultStatus(false);
$limit = 100;
$projectCursor = null;
while (true) {
$projectsQueries = [Query::limit($limit)];
if ($projectCursor !== null) {
$projectsQueries[] = Query::cursorAfter($projectCursor);
}
$projects = $dbForConsole->find('projects', $projectsQueries);
if (count($projects) === 0) {
Console::info("**** Could not found any projects ****");
break;
}
foreach ($projects as $project) {
Console::info(PHP_EOL . "Project " . $project->getAttribute('name') . " (" . $project->getInternalId() . ")");
$dbForProject = $getProjectDB($project);
if ($commit) {
try {
$dbForProject->renameAttribute('stats', 'metric', 'metricOld');
$dbForProject->renameAttribute('stats', 'metricV2', 'metric');
Console::log("Commit -Renaming stats column metric to metricOld, metricV2 to metric");
} catch (\Throwable $th) {
Console::Error("Error while trying to rename col: {$th->getMessage()}");
}
continue;
}
if ($rollback) {
try {
$dbForProject->renameAttribute('stats', 'metric', 'metricV2');
$dbForProject->renameAttribute('stats', 'metricOld', 'metric');
Console::log("Rollback - Renaming stats column metric to metricV2, metricOld to metric");
} catch (\Throwable $th) {
Console::Error("Error while trying to rename column: {$th->getMessage()}");
}
continue;
}
/**
* Project level
*/
$metrics = [];
$metrics[] = ['from' => 'project.$all.network.outbound', 'to' => 'network.outbound'];
$metrics[] = ['from' => 'project.$all.network.inbound', 'to' => 'network.inbound'];
$metrics[] = ['from' => 'project.$all.network.requests', 'to' => 'network.requests'];
$metrics[] = ['from' => 'executions.$all.compute.total', 'to' => 'executions'];
$metrics[] = ['from' => 'executions.$all.compute.time', 'to' => 'executions.compute'];
$metrics[] = ['from' => 'builds.$all.compute.total', 'to' => 'builds'];
$metrics[] = ['from' => 'builds.$all.compute.time', 'to' => 'builds.compute'];
$metrics[] = ['from' => 'files.$all.storage.size', 'to' => 'files.storage'];
$metrics[] = ['from' => 'files.$all.count.total', 'to' => 'files'];
$metrics[] = ['from' => 'buckets.$all.count.total', 'to' => 'buckets'];
$metrics[] = ['from' => 'collections.$all.count.total', 'to' => 'collections'];
$metrics[] = ['from' => 'databases.$all.count.total', 'to' => 'databases'];
$metrics[] = ['from' => 'documents.$all.count.total', 'to' => 'documents'];
$metrics[] = ['from' => 'users.$all.count.total ', 'to' => 'users'];
foreach ($metrics as $metric) {
$stats = $dbForProject->find('stats', [
Query::equal('metric', [$metric['from']]),
Query::greaterThan('value', 0)
]);
foreach ($stats as $stat) {
$stat->setAttribute('metricV2', $metric['to']);
$dbForProject->updateDocument('stats', $stat->getId(), $stat);
Console::log($stat->getId() . ', ' . $metric['from'] . ', ' . $metric['to'] . ', ' . $stat['period'] . ', ' . $stat['value']);
}
}
/**
* Buckets, Files
*/
$buckets = $dbForProject->find('buckets', []);
foreach ($buckets as $bucket) {
$metrics = [];
$metrics[] = [
'from' => str_replace('{bucketId}', $bucket->getId(), 'files.{bucketId}.count.total'),
'to' => str_replace('{bucketInternalId}', $bucket->getInternalId(), '{bucketInternalId}.files')
];
$metrics[] = [
'from' => str_replace('{bucketId}', $bucket->getId(), 'files.{bucketId}.storage.size'),
'to' => str_replace('{bucketInternalId}', $bucket->getInternalId(), '{bucketInternalId}.files.storage')
];
foreach ($metrics as $metric) {
$stats = $dbForProject->find('stats', [
Query::equal('metric', [$metric['from']]),
Query::greaterThan('value', 0)
]);
foreach ($stats as $stat) {
$stat->setAttribute('metricV2', $metric['to']);
$dbForProject->updateDocument('stats', $stat->getId(), $stat);
Console::log($stat->getId() . ', ' . $metric['from'] . ', ' . $metric['to'] . ', ' . $stat['period']);
}
}
}
/**
* Databases, collections, documents
*/
$databases = $dbForProject->find('databases', []);
foreach ($databases as $database) {
$metrics = [];
$metrics[] = [
'from' => str_replace('{databaseId}', $database->getId(), 'documents.{databaseId}.count.total'),
'to' => str_replace('{databaseInternalId}', $database->getInternalId(), '{databaseInternalId}.collections')];
$metrics[] = [
'from' => str_replace('{databaseId}', $database->getId(), 'documents.{databaseId}.count.total'),
'to' => str_replace('{databaseInternalId}', $database->getInternalId(), '{databaseInternalId}.documents')];
foreach ($metrics as $metric) {
$stats = $dbForProject->find('stats', [
Query::equal('metric', [$metric['from']]),
Query::greaterThan('value', 0)
]);
foreach ($stats as $stat) {
$stat->setAttribute('metricV2', $metric['to']);
$dbForProject->updateDocument('stats', $stat->getId(), $stat);
Console::log($stat->getId() . ', ' . $metric['from'] . ', ' . $metric['to'] . ', ' . $stat['period']);
}
$collections = $dbForProject->find('database_' . $database->getInternalId(), []);
foreach ($collections as $collection) {
$__metric = [
'from' => str_replace(['{databaseId}', '{collectionId}'], [$database->getId(), $collection->getId()], 'documents.{databaseId}/{collectionId}.count.total'),
'to' => str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$database->getInternalId(), $collection->getInternalId()], '{databaseInternalId}.{collectionInternalId}.documents')];
$__stats = $dbForProject->find('stats', [
Query::equal('metric', [$__metric['from']]),
Query::greaterThan('value', 0)
]);
foreach ($__stats as $__stat) {
$__stat->setAttribute('metricV2', $__metric['to']);
$dbForProject->updateDocument('stats', $__stat->getId(), $__stat);
Console::log($__stat->getId() . ', ' . $__metric['from'] . ', ' . $__metric['to'] . ', ' . $__stat['period']);
}
}
}
}
/**
* executions
*/
$functions = $dbForProject->find('functions', []);
foreach ($functions as $function) {
$metrics = [];
$metrics[] = [
'from' => str_replace('{functionId}', $function->getId(), 'executions.{functionId}.compute.time'),
'to' => str_replace('{functionInternalId}', $function->getInternalId(), '{functionInternalId}.executions.compute')
];
$metrics[] = [
'from' => str_replace('{functionId}', $function->getId(), 'executions.{functionId}.compute.total'),
'to' => str_replace('{functionInternalId}', $function->getInternalId(), '{functionInternalId}.executions')
];
$metrics[] = [
'from' => str_replace('{functionId}', $function->getId(), 'builds.{functionId}.compute.total'),
'to' => str_replace('{functionInternalId}', $function->getInternalId(), '{functionInternalId}.builds')
];
$metrics[] = [
'from' => str_replace('{functionId}', $function->getId(), 'builds.{functionId}.compute.time'),
'to' => str_replace('{functionInternalId}', $function->getInternalId(), '{functionInternalId}.compute')
];
foreach ($metrics as $metric) {
$stats = $dbForProject->find('stats', [
Query::equal('metric', [$metric['from']]),
Query::greaterThan('value', 0)
]);
foreach ($stats as $stat) {
$stat->setAttribute('metricV2', $metric['to']);
$dbForProject->updateDocument('stats', $stat->getId(), $stat);
Console::log($stat->getId() . ', ' . $metric['from'] . ', ' . $metric['to'] . ', ' . $stat['period']);
}
}
}
}
$projectCursor = $projects[array_key_last($projects)];
}
}
}