Added function usage tracking

This commit is contained in:
Eldad Fux
2020-07-21 13:33:23 +03:00
parent 1282be6132
commit c65ef9e6a8
9 changed files with 160 additions and 17 deletions
+98
View File
@@ -112,6 +112,104 @@ App::get('/v1/functions/:functionId')
$response->json($function->getArrayCopy());
}, ['response', 'projectDB']);
App::get('/v1/functions/:functionId/usage')
->desc('Get Function Usage')
->groups(['api', 'functions'])
->label('scope', 'functions.read')
->label('sdk.namespace', 'functions')
->label('sdk.method', 'getUsage')
->param('functionId', '', function () { return new UID(); }, 'Function unique ID.')
->param('range', 'last30', function () { return new WhiteList(['daily', 'monthly', 'last30', 'last90']); }, 'Date range.', true)
->action(function ($functionId, $range, $response, $project, $projectDB, $register) {
/** @var Utopia\Response $response */
/** @var Appwrite\Database\Document $project */
/** @var Appwrite\Database\Database $consoleDB */
/** @var Appwrite\Database\Database $projectDB */
/** @var Utopia\Registry\Registry $register */
$function = $projectDB->getDocument($functionId);
if (empty($function->getId()) || Database::SYSTEM_COLLECTION_FUNCTIONS != $function->getCollection()) {
throw new Exception('function not found', 404);
}
$period = [
'daily' => [
'start' => DateTime::createFromFormat('U', \strtotime('today')),
'end' => DateTime::createFromFormat('U', \strtotime('tomorrow')),
'group' => '1m',
],
'monthly' => [
'start' => DateTime::createFromFormat('U', \strtotime('midnight first day of this month')),
'end' => DateTime::createFromFormat('U', \strtotime('midnight last day of this month')),
'group' => '1d',
],
'last30' => [
'start' => DateTime::createFromFormat('U', \strtotime('-30 days')),
'end' => DateTime::createFromFormat('U', \strtotime('tomorrow')),
'group' => '1d',
],
'last90' => [
'start' => DateTime::createFromFormat('U', \strtotime('-90 days')),
'end' => DateTime::createFromFormat('U', \strtotime('today')),
'group' => '1d',
],
// 'yearly' => [
// 'start' => DateTime::createFromFormat('U', strtotime('midnight first day of january')),
// 'end' => DateTime::createFromFormat('U', strtotime('midnight last day of december')),
// 'group' => '4w',
// ],
];
$client = $register->get('influxdb');
$executions = [];
$compute = [];
if ($client) {
$start = $period[$range]['start']->format(DateTime::RFC3339);
$end = $period[$range]['end']->format(DateTime::RFC3339);
$database = $client->selectDB('telegraf');
// Executions
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_executions_all" WHERE time > \''.$start.'\' AND time < \''.$end.'\' AND "metric_type"=\'counter\' AND "project"=\''.$project->getId().'\' AND "functionId"=\''.$function->getId().'\' GROUP BY time('.$period[$range]['group'].') FILL(null)');
$points = $result->getPoints();
foreach ($points as $point) {
$executions[] = [
'value' => (!empty($point['value'])) ? $point['value'] : 0,
'date' => \strtotime($point['time']),
];
}
// Compute
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_executions_time" WHERE time > \''.$start.'\' AND time < \''.$end.'\' AND "metric_type"=\'counter\' AND "project"=\''.$project->getId().'\' AND "functionId"=\''.$function->getId().'\' GROUP BY time('.$period[$range]['group'].') FILL(null)');
$points = $result->getPoints();
foreach ($points as $point) {
$compute[] = [
'value' => (!empty($point['value'])) ? $point['value'] : 0,
'date' => \strtotime($point['time']),
];
}
}
$response->json([
'executions' => [
'data' => $executions,
'total' => \array_sum(\array_map(function ($item) {
return $item['value'];
}, $executions)),
],
'compute' => [
'data' => $compute,
'total' => \array_sum(\array_map(function ($item) {
return $item['value'];
}, $compute)),
],
]);
}, ['response', 'consoleDB', 'projectDB', 'register']);
App::put('/v1/functions/:functionId')
->groups(['api', 'functions'])
->desc('Update Function')
+18
View File
@@ -206,6 +206,7 @@ App::get('/v1/projects/:projectId/usage')
$requests = [];
$network = [];
$functions = [];
if ($client) {
$start = $period[$range]['start']->format(DateTime::RFC3339);
@@ -233,6 +234,17 @@ App::get('/v1/projects/:projectId/usage')
'date' => \strtotime($point['time']),
];
}
// Functions
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_executions_all" WHERE time > \''.$start.'\' AND time < \''.$end.'\' AND "metric_type"=\'counter\' AND "project"=\''.$project->getId().'\' GROUP BY time('.$period[$range]['group'].') FILL(null)');
$points = $result->getPoints();
foreach ($points as $point) {
$functions[] = [
'value' => (!empty($point['value'])) ? $point['value'] : 0,
'date' => \strtotime($point['time']),
];
}
}
// Users
@@ -289,6 +301,12 @@ App::get('/v1/projects/:projectId/usage')
return $item['value'];
}, $network)),
],
'functions' => [
'data' => $functions,
'total' => \array_sum(\array_map(function ($item) {
return $item['value'];
}, $functions)),
],
'collections' => [
'data' => $collections,
'total' => $collectionsTotal,
+4 -4
View File
@@ -277,8 +277,8 @@ $timeout = $this->getParam('timeout', 900);
<thead>
<tr>
<th width="30"></th>
<th width="170">Triggered</th>
<th width="150">Status</th>
<th width="170">Date</th>
<th width="100">Runtime</th>
<th></th>
</tr>
@@ -291,13 +291,13 @@ $timeout = $this->getParam('timeout', 900);
<i class="dot info" data-ls-if="{{execution.status}} === 'processing'"></i>
<i class="dot success" data-ls-if="{{execution.status}} === 'completed'"></i>
</td>
<td data-title="Date: ">
<span data-ls-bind="{{execution.dateCreated|dateTime}}"></span>
</td>
<td data-title="Status: ">
<span data-ls-bind="{{execution.status}}"></span>
<span class="text-fade text-size-small" data-ls-if="{{execution.exitCode}} !== 0" data-ls-bind=" exit code: {{execution.exitCode}}"></span>
</td>
<td data-title="Date: ">
<span data-ls-bind="{{execution.dateCreated|dateTime}}"></span>
</td>
<td data-title="Runtime: ">
<span data-ls-if="{{execution.status}} === 'completed' || {{execution.status}} === 'failed'" data-ls-bind="{{execution.time|seconds2hum}}"></span>
<span data-ls-if="{{execution.status}} === 'waiting' || {{execution.status}} === 'processing'">-</span>
+11 -1
View File
@@ -23,7 +23,7 @@ $graph = $this->getParam('graph', false);
</div>
</div>
<div class="zone xl margin-top-negative-xxl">
<div class="zone xxl margin-top-negative-xxl">
<div class="box margin-bottom dashboard">
<div
data-service="projects.getUsage"
@@ -52,6 +52,8 @@ $graph = $this->getParam('graph', false);
<!-- <div class="margin-top dev-feature">
<a href="">Full Usage Report <i class="icon-right-open"></i></a>
</div> -->
<div class="margin-top-large"><b class="text-size-small unit" data-ls-bind="{{usage.functions.total|statsTotal}} Func. Executed" data-default="0 Func. Executed"></b></div>
</div>
</div>
@@ -77,6 +79,14 @@ $graph = $this->getParam('graph', false);
<div class="margin-top-small"><b class="text-size-small unit">Tasks</b></div>
</div>
</div>
<!--
<hr />
<div class="row responsive">
<div class="col span-4">x</div>
<div class="col span-4">x</div>
<div class="col span-4">x</div>
</div> -->
</div>
</div>
</div>
+15 -1
View File
@@ -302,6 +302,7 @@ class FunctionsV1
, null, $stdout, $stderr, $function->getAttribute('timeout', (int) App::getEnv('_APP_FUNCTIONS_TIMEOUT', 900)));
$executionEnd = \microtime(true);
$executionTime = ($executionEnd - $executionStart);
Console::info("Function executed in " . ($executionEnd - $executionStart) . " seconds with exit code {$exitCode}");
@@ -313,7 +314,7 @@ class FunctionsV1
'exitCode' => $exitCode,
'stdout' => mb_substr($stdout, -4000), // log last 4000 chars output
'stderr' => mb_substr($stderr, -4000), // log last 4000 chars output
'time' => ($executionEnd - $executionStart),
'time' => $executionTime,
]));
Authorization::reset();
@@ -322,6 +323,19 @@ class FunctionsV1
throw new Exception('Failed saving execution to DB', 500);
}
$usage = $register->get('queue-usage');
$usage
->setParam('projectId', $projectId)
->setParam('functionId', $function->getId())
->setParam('functionExecution', 1)
->setParam('functionExecutionTime', $executionTime) // Seconds
->setParam('networkRequestSize', 0)
->setParam('networkResponseSize', 0)
;
$usage->trigger();
Console::success(count($list).' running containers counted');
$max = (int) App::getEnv('_APP_FUNCTIONS_CONTAINERS');
+11 -7
View File
@@ -27,17 +27,18 @@ class UsageV1
$statsd = $register->get('statsd', true);
$projectId = $this->args['projectId'];
$httpMethod = $this->args['httpMethod'];
$httpRequest = $this->args['httpRequest'];
$storage = $this->args['storage'];
$networkRequestSize = $this->args['networkRequestSize'];
$networkResponseSize = $this->args['networkResponseSize'];
$storage = $this->args['storage'];
$httpMethod = $this->args['httpMethod'];
$httpRequest = $this->args['httpRequest'];
$functionId = $this->args['functionId'];
$functionExecution = $this->args['functionExecution'];
$functionExecutionTime = $this->args['functionExecutionTime'];
$functionId = $this->args['functionId'];
$tags = ",project={$projectId},version=".App::getEnv('_APP_VERSION', 'UNKNOWN').'';
@@ -53,10 +54,13 @@ class UsageV1
$statsd->count('executions.time'.$tags.',functionId='.$functionId, $functionExecutionTime);
}
$statsd->count('network.all'.$tags, $networkRequestSize + $networkResponseSize);
$statsd->count('network.inbound'.$tags, $networkRequestSize);
$statsd->count('network.outbound'.$tags, $networkResponseSize);
$statsd->count('storage.all'.$tags, $storage);
$statsd->count('network.all'.$tags, $networkRequestSize + $networkResponseSize);
if($storage >= 1) {
$statsd->count('storage.all'.$tags, $storage);
}
}
public function tearDown()
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -2
View File
@@ -422,7 +422,7 @@
}
hr {
margin: 20px -20px;
margin: 20px -25px;
height: 2px;
background: var(--config-console-background);
@@ -452,7 +452,6 @@
display: block;
width: 2px;
background: var(--config-console-background);
height: ~"calc(100% + 110px)";
position: absolute;
top: -20px;
bottom: -20px;