mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
feat(sites): add screenshot success telemetry to usage stats
This commit is contained in:
@@ -351,6 +351,8 @@ const METRIC_BUILDS_STORAGE = 'builds.storage';
|
||||
const METRIC_BUILDS_COMPUTE = 'builds.compute';
|
||||
const METRIC_BUILDS_COMPUTE_SUCCESS = 'builds.compute.success';
|
||||
const METRIC_BUILDS_COMPUTE_FAILED = 'builds.compute.failed';
|
||||
const METRIC_SCREENSHOTS_SUCCESS = 'screenshots.success';
|
||||
const METRIC_SCREENSHOTS_FAILED = 'screenshots.failed';
|
||||
const METRIC_BUILDS_MB_SECONDS = 'builds.mbSeconds';
|
||||
const METRIC_EXECUTIONS = 'executions';
|
||||
const METRIC_EXECUTIONS_COMPUTE = 'executions.compute';
|
||||
@@ -363,6 +365,8 @@ const METRIC_RESOURCE_TYPE_ID_BUILDS_FAILED = '{resourceType}.{resourceInternal
|
||||
const METRIC_RESOURCE_TYPE_ID_BUILDS_COMPUTE = '{resourceType}.{resourceInternalId}.builds.compute';
|
||||
const METRIC_RESOURCE_TYPE_ID_BUILDS_COMPUTE_SUCCESS = '{resourceType}.{resourceInternalId}.builds.compute.success';
|
||||
const METRIC_RESOURCE_TYPE_ID_BUILDS_COMPUTE_FAILED = '{resourceType}.{resourceInternalId}.builds.compute.failed';
|
||||
const METRIC_RESOURCE_TYPE_ID_SCREENSHOTS_SUCCESS = '{resourceType}.{resourceInternalId}.screenshots.success';
|
||||
const METRIC_RESOURCE_TYPE_ID_SCREENSHOTS_FAILED = '{resourceType}.{resourceInternalId}.screenshots.failed';
|
||||
const METRIC_RESOURCE_TYPE_ID_BUILDS_MB_SECONDS = '{resourceType}.{resourceInternalId}.builds.mbSeconds';
|
||||
const METRIC_RESOURCE_TYPE_ID_BUILDS = '{resourceType}.{resourceInternalId}.builds';
|
||||
const METRIC_RESOURCE_TYPE_ID_BUILDS_STORAGE = '{resourceType}.{resourceInternalId}.builds.storage';
|
||||
@@ -376,6 +380,8 @@ const METRIC_RESOURCE_TYPE_BUILDS_FAILED = '{resourceType}.builds.failed';
|
||||
const METRIC_RESOURCE_TYPE_BUILDS_COMPUTE = '{resourceType}.builds.compute';
|
||||
const METRIC_RESOURCE_TYPE_BUILDS_COMPUTE_SUCCESS = '{resourceType}.builds.compute.success';
|
||||
const METRIC_RESOURCE_TYPE_BUILDS_COMPUTE_FAILED = '{resourceType}.builds.compute.failed';
|
||||
const METRIC_RESOURCE_TYPE_SCREENSHOTS_SUCCESS = '{resourceType}.screenshots.success';
|
||||
const METRIC_RESOURCE_TYPE_SCREENSHOTS_FAILED = '{resourceType}.screenshots.failed';
|
||||
const METRIC_RESOURCE_TYPE_BUILDS_MB_SECONDS = '{resourceType}.builds.mbSeconds';
|
||||
const METRIC_RESOURCE_TYPE_BUILDS = '{resourceType}.builds';
|
||||
const METRIC_RESOURCE_TYPE_BUILDS_STORAGE = '{resourceType}.builds.storage';
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
namespace Appwrite\Platform\Modules\Functions\Workers;
|
||||
|
||||
use Ahc\Jwt\JWT;
|
||||
use Appwrite\Event\Message\Usage as UsageMessage;
|
||||
use Appwrite\Event\Publisher\Usage as UsagePublisher;
|
||||
use Appwrite\Event\Realtime;
|
||||
use Appwrite\Permission;
|
||||
use Appwrite\Role;
|
||||
use Appwrite\Usage\Context;
|
||||
use Exception;
|
||||
use Utopia\Compression\Compression;
|
||||
use Utopia\Config\Config;
|
||||
@@ -43,6 +46,7 @@ class Screenshots extends Action
|
||||
->inject('dbForProject')
|
||||
->inject('project')
|
||||
->inject('deviceForFiles')
|
||||
->inject('publisherForUsage')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
@@ -52,7 +56,8 @@ class Screenshots extends Action
|
||||
Database $dbForPlatform,
|
||||
Database $dbForProject,
|
||||
Document $project,
|
||||
Device $deviceForFiles
|
||||
Device $deviceForFiles,
|
||||
UsagePublisher $publisherForUsage
|
||||
): void {
|
||||
Console::log('Screenshot action started');
|
||||
|
||||
@@ -257,6 +262,13 @@ class Screenshots extends Action
|
||||
'deploymentScreenshotDark' => $deployment->getAttribute('screenshotDark', ''),
|
||||
'deploymentScreenshotLight' => $deployment->getAttribute('screenshotLight', ''),
|
||||
]));
|
||||
|
||||
$this->publishUsage(
|
||||
project: $project,
|
||||
site: $site,
|
||||
publisherForUsage: $publisherForUsage,
|
||||
metric: METRIC_SCREENSHOTS_SUCCESS
|
||||
);
|
||||
} catch (\Throwable $th) {
|
||||
Console::warning("Screenshot failed to generate:");
|
||||
Console::warning($th->getMessage());
|
||||
@@ -265,10 +277,51 @@ class Screenshots extends Action
|
||||
$date = \date('H:i:s');
|
||||
$this->appendToLogs($dbForProject, $deployment->getId(), $queueForRealtime, "[90m[$date] [90m[[0mappwrite[90m][33m Screenshot capturing failed. Deployment will continue. [0m\n");
|
||||
|
||||
$this->publishUsage(
|
||||
project: $project,
|
||||
site: $site,
|
||||
publisherForUsage: $publisherForUsage,
|
||||
metric: METRIC_SCREENSHOTS_FAILED
|
||||
);
|
||||
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
|
||||
protected function publishUsage(
|
||||
Document $project,
|
||||
Document $site,
|
||||
UsagePublisher $publisherForUsage,
|
||||
string $metric
|
||||
): void {
|
||||
[$resourceMetric, $resourceIdMetric] = match ($metric) {
|
||||
METRIC_SCREENSHOTS_SUCCESS => [
|
||||
METRIC_RESOURCE_TYPE_SCREENSHOTS_SUCCESS,
|
||||
METRIC_RESOURCE_TYPE_ID_SCREENSHOTS_SUCCESS,
|
||||
],
|
||||
METRIC_SCREENSHOTS_FAILED => [
|
||||
METRIC_RESOURCE_TYPE_SCREENSHOTS_FAILED,
|
||||
METRIC_RESOURCE_TYPE_ID_SCREENSHOTS_FAILED,
|
||||
],
|
||||
default => throw new \InvalidArgumentException('Unknown screenshot metric: ' . $metric),
|
||||
};
|
||||
|
||||
$usage = (new Context())
|
||||
->addMetric($metric, 1)
|
||||
->addMetric(str_replace('{resourceType}', RESOURCE_TYPE_SITES, $resourceMetric), 1)
|
||||
->addMetric(str_replace(
|
||||
['{resourceType}', '{resourceInternalId}'],
|
||||
[RESOURCE_TYPE_SITES, $site->getSequence()],
|
||||
$resourceIdMetric
|
||||
), 1);
|
||||
|
||||
$publisherForUsage->enqueue(new UsageMessage(
|
||||
project: $project,
|
||||
metrics: $usage->getMetrics(),
|
||||
reduce: $usage->getReduce()
|
||||
));
|
||||
}
|
||||
|
||||
protected function appendToLogs(Database $dbForProject, string $deploymentId, Realtime $queueForRealtime, string $logs)
|
||||
{
|
||||
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
|
||||
|
||||
@@ -87,6 +87,8 @@ class Get extends Base
|
||||
str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_SITES, $site->getSequence()], METRIC_RESOURCE_TYPE_ID_EXECUTIONS_MB_SECONDS),
|
||||
str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_SITES, $site->getSequence()], METRIC_RESOURCE_TYPE_ID_BUILDS_SUCCESS),
|
||||
str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_SITES, $site->getSequence()], METRIC_RESOURCE_TYPE_ID_BUILDS_FAILED),
|
||||
str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_SITES, $site->getSequence()], METRIC_RESOURCE_TYPE_ID_SCREENSHOTS_SUCCESS),
|
||||
str_replace(['{resourceType}', '{resourceInternalId}'], [RESOURCE_TYPE_SITES, $site->getSequence()], METRIC_RESOURCE_TYPE_ID_SCREENSHOTS_FAILED),
|
||||
str_replace(['{siteInternalId}'], [$site->getSequence()], METRIC_SITES_ID_REQUESTS),
|
||||
str_replace(['{siteInternalId}'], [$site->getSequence()], METRIC_SITES_ID_INBOUND),
|
||||
str_replace(['{siteInternalId}'], [$site->getSequence()], METRIC_SITES_ID_OUTBOUND),
|
||||
@@ -139,6 +141,9 @@ class Get extends Base
|
||||
|
||||
$buildsTimeTotal = $usage[$metrics[4]]['total'] ?? 0;
|
||||
$buildsTotal = $usage[$metrics[2]]['total'] ?? 0;
|
||||
$screenshotsSuccessTotal = $usage[$metrics[11]]['total'] ?? 0;
|
||||
$screenshotsFailedTotal = $usage[$metrics[12]]['total'] ?? 0;
|
||||
$screenshotsTotal = $screenshotsSuccessTotal + $screenshotsFailedTotal;
|
||||
$response->dynamic(new Document([
|
||||
'range' => $range,
|
||||
'deploymentsTotal' => $usage[$metrics[0]]['total'],
|
||||
@@ -153,9 +158,12 @@ class Get extends Base
|
||||
'executionsMbSecondsTotal' => $usage[$metrics[8]]['total'],
|
||||
'buildsSuccessTotal' => $usage[$metrics[9]]['total'],
|
||||
'buildsFailedTotal' => $usage[$metrics[10]]['total'],
|
||||
'requestsTotal' => $usage[$metrics[11]]['total'],
|
||||
'inboundTotal' => $usage[$metrics[12]]['total'],
|
||||
'outboundTotal' => $usage[$metrics[13]]['total'],
|
||||
'screenshotsSuccessTotal' => $screenshotsSuccessTotal,
|
||||
'screenshotsFailedTotal' => $screenshotsFailedTotal,
|
||||
'screenshotsSuccessRate' => $screenshotsTotal === 0 ? 0 : $screenshotsSuccessTotal / $screenshotsTotal,
|
||||
'requestsTotal' => $usage[$metrics[13]]['total'],
|
||||
'inboundTotal' => $usage[$metrics[14]]['total'],
|
||||
'outboundTotal' => $usage[$metrics[15]]['total'],
|
||||
'deployments' => $usage[$metrics[0]]['data'],
|
||||
'deploymentsStorage' => $usage[$metrics[1]]['data'],
|
||||
'builds' => $usage[$metrics[2]]['data'],
|
||||
@@ -167,9 +175,11 @@ class Get extends Base
|
||||
'executionsMbSeconds' => $usage[$metrics[8]]['data'],
|
||||
'buildsSuccess' => $usage[$metrics[9]]['data'],
|
||||
'buildsFailed' => $usage[$metrics[10]]['data'],
|
||||
'requests' => $usage[$metrics[11]]['data'],
|
||||
'inbound' => $usage[$metrics[12]]['data'],
|
||||
'outbound' => $usage[$metrics[13]]['data'],
|
||||
'screenshotsSuccess' => $usage[$metrics[11]]['data'],
|
||||
'screenshotsFailed' => $usage[$metrics[12]]['data'],
|
||||
'requests' => $usage[$metrics[13]]['data'],
|
||||
'inbound' => $usage[$metrics[14]]['data'],
|
||||
'outbound' => $usage[$metrics[15]]['data'],
|
||||
]), Response::MODEL_USAGE_SITE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,8 @@ class XList extends Base
|
||||
str_replace("{resourceType}", RESOURCE_TYPE_SITES, METRIC_RESOURCE_TYPE_EXECUTIONS_MB_SECONDS),
|
||||
str_replace("{resourceType}", RESOURCE_TYPE_SITES, METRIC_RESOURCE_TYPE_BUILDS_SUCCESS),
|
||||
str_replace("{resourceType}", RESOURCE_TYPE_SITES, METRIC_RESOURCE_TYPE_BUILDS_FAILED),
|
||||
str_replace("{resourceType}", RESOURCE_TYPE_SITES, METRIC_RESOURCE_TYPE_SCREENSHOTS_SUCCESS),
|
||||
str_replace("{resourceType}", RESOURCE_TYPE_SITES, METRIC_RESOURCE_TYPE_SCREENSHOTS_FAILED),
|
||||
METRIC_SITES_REQUESTS,
|
||||
METRIC_SITES_INBOUND,
|
||||
METRIC_SITES_OUTBOUND,
|
||||
@@ -122,6 +124,10 @@ class XList extends Base
|
||||
];
|
||||
}
|
||||
}
|
||||
$screenshotsSuccessTotal = $usage[$metrics[12]]['total'] ?? 0;
|
||||
$screenshotsFailedTotal = $usage[$metrics[13]]['total'] ?? 0;
|
||||
$screenshotsTotal = $screenshotsSuccessTotal + $screenshotsFailedTotal;
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'range' => $range,
|
||||
'sitesTotal' => $usage[$metrics[0]]['total'],
|
||||
@@ -136,9 +142,12 @@ class XList extends Base
|
||||
'executionsMbSecondsTotal' => $usage[$metrics[9]]['total'],
|
||||
'buildsSuccessTotal' => $usage[$metrics[10]]['total'],
|
||||
'buildsFailedTotal' => $usage[$metrics[11]]['total'],
|
||||
'requestsTotal' => $usage[$metrics[12]]['total'],
|
||||
'inboundTotal' => $usage[$metrics[13]]['total'],
|
||||
'outboundTotal' => $usage[$metrics[14]]['total'],
|
||||
'screenshotsSuccessTotal' => $screenshotsSuccessTotal,
|
||||
'screenshotsFailedTotal' => $screenshotsFailedTotal,
|
||||
'screenshotsSuccessRate' => $screenshotsTotal === 0 ? 0 : $screenshotsSuccessTotal / $screenshotsTotal,
|
||||
'requestsTotal' => $usage[$metrics[14]]['total'],
|
||||
'inboundTotal' => $usage[$metrics[15]]['total'],
|
||||
'outboundTotal' => $usage[$metrics[16]]['total'],
|
||||
'sites' => $usage[$metrics[0]]['data'],
|
||||
'deployments' => $usage[$metrics[1]]['data'],
|
||||
'deploymentsStorage' => $usage[$metrics[2]]['data'],
|
||||
@@ -151,9 +160,11 @@ class XList extends Base
|
||||
'executionsMbSeconds' => $usage[$metrics[9]]['data'],
|
||||
'buildsSuccess' => $usage[$metrics[10]]['data'],
|
||||
'buildsFailed' => $usage[$metrics[11]]['data'],
|
||||
'requests' => $usage[$metrics[12]]['data'],
|
||||
'inbound' => $usage[$metrics[13]]['data'],
|
||||
'outbound' => $usage[$metrics[14]]['data'],
|
||||
'screenshotsSuccess' => $usage[$metrics[12]]['data'],
|
||||
'screenshotsFailed' => $usage[$metrics[13]]['data'],
|
||||
'requests' => $usage[$metrics[14]]['data'],
|
||||
'inbound' => $usage[$metrics[15]]['data'],
|
||||
'outbound' => $usage[$metrics[16]]['data'],
|
||||
]), Response::MODEL_USAGE_SITES);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,38 @@ class UsageSite extends UsageFunction
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('screenshotsSuccessTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated number of successful site screenshots.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('screenshotsFailedTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated number of failed site screenshots.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('screenshotsSuccessRate', [
|
||||
'type' => self::TYPE_FLOAT,
|
||||
'description' => 'Success rate of site screenshots from 0 to 1.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('screenshotsSuccess', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated number of successful site screenshots per period.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('screenshotsFailed', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated number of failed site screenshots per period.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
@@ -122,6 +122,38 @@ class UsageSites extends Model
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('screenshotsSuccessTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated number of successful site screenshots.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('screenshotsFailedTotal', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Total aggregated number of failed site screenshots.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('screenshotsSuccessRate', [
|
||||
'type' => self::TYPE_FLOAT,
|
||||
'description' => 'Success rate of site screenshots from 0 to 1.',
|
||||
'default' => 0,
|
||||
'example' => 0,
|
||||
])
|
||||
->addRule('screenshotsSuccess', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated number of successful site screenshots per period.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('screenshotsFailed', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated number of failed site screenshots per period.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('deployments', [
|
||||
'type' => Response::MODEL_METRIC,
|
||||
'description' => 'Aggregated number of sites deployment per period.',
|
||||
|
||||
@@ -1675,11 +1675,14 @@ class UsageTest extends Scope
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(30, count($response['body']));
|
||||
$this->assertEquals(35, count($response['body']));
|
||||
$this->assertEquals('30d', $response['body']['range']);
|
||||
$this->assertIsArray($response['body']['deployments']);
|
||||
$this->assertEquals($deploymentsSuccess, $response['body']['buildsSuccessTotal']);
|
||||
$this->assertEquals($deploymentsFailed, $response['body']['buildsFailedTotal']);
|
||||
$this->assertGreaterThanOrEqual(1, $response['body']['screenshotsSuccessTotal']);
|
||||
$this->assertEquals(0, $response['body']['screenshotsFailedTotal']);
|
||||
$this->assertEquals(1.0, $response['body']['screenshotsSuccessRate']);
|
||||
$this->assertIsArray($response['body']['deploymentsStorage']);
|
||||
$this->assertIsNumeric($response['body']['deploymentsStorageTotal']);
|
||||
$this->assertIsNumeric($response['body']['buildsMbSecondsTotal']);
|
||||
@@ -1692,6 +1695,8 @@ class UsageTest extends Scope
|
||||
$this->assertIsArray($response['body']['executionsMbSeconds']);
|
||||
$this->assertIsArray($response['body']['buildsSuccess']);
|
||||
$this->assertIsArray($response['body']['buildsFailed']);
|
||||
$this->assertIsArray($response['body']['screenshotsSuccess']);
|
||||
$this->assertIsArray($response['body']['screenshotsFailed']);
|
||||
$this->assertIsArray($response['body']['requests']);
|
||||
$this->assertIsArray($response['body']['inbound']);
|
||||
$this->assertIsArray($response['body']['outbound']);
|
||||
@@ -1709,7 +1714,7 @@ class UsageTest extends Scope
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(31, count($response['body']));
|
||||
$this->assertEquals(36, count($response['body']));
|
||||
$this->assertEquals($response['body']['range'], '30d');
|
||||
$this->assertIsArray($response['body']['sites']);
|
||||
$this->assertIsArray($response['body']['deployments']);
|
||||
@@ -1722,6 +1727,11 @@ class UsageTest extends Scope
|
||||
$this->assertIsArray($response['body']['executionsMbSeconds']);
|
||||
$this->assertIsArray($response['body']['buildsSuccess']);
|
||||
$this->assertIsArray($response['body']['buildsFailed']);
|
||||
$this->assertGreaterThanOrEqual(1, $response['body']['screenshotsSuccessTotal']);
|
||||
$this->assertEquals(0, $response['body']['screenshotsFailedTotal']);
|
||||
$this->assertEquals(1.0, $response['body']['screenshotsSuccessRate']);
|
||||
$this->assertIsArray($response['body']['screenshotsSuccess']);
|
||||
$this->assertIsArray($response['body']['screenshotsFailed']);
|
||||
$this->assertIsArray($response['body']['requests']);
|
||||
$this->assertIsArray($response['body']['inbound']);
|
||||
$this->assertIsArray($response['body']['outbound']);
|
||||
|
||||
Reference in New Issue
Block a user