Compare commits

...
Author SHA1 Message Date
Khushboo Verma 343ded16a8 Truncate logs to a limit 2025-08-20 17:28:35 +05:30
6 changed files with 79 additions and 3 deletions
+13 -1
View File
@@ -618,7 +618,19 @@ function router(App $utopia, Database $dbForPlatform, callable $getProjectDB, Sw
/** Update execution status */
$status = $executionResponse['statusCode'] >= 500 ? 'failed' : 'completed';
$execution->setAttribute('status', $status);
$execution->setAttribute('logs', $executionResponse['logs']);
// Truncate logs if they exceed the limit
$maxLogLength = APP_FUNCTION_LOG_LENGTH_LIMIT;
$logs = $executionResponse['logs'] ?? '';
if (\is_string($logs) && \strlen($logs) > $maxLogLength) {
$warningMessage = "\n[WARNING] Logs truncated. The output exceeded {$maxLogLength} characters.";
$warningLength = \strlen($warningMessage);
$maxContentLength = $maxLogLength - $warningLength;
$logs = \substr($logs, 0, $maxContentLength) . $warningMessage;
}
$execution->setAttribute('logs', $logs);
$execution->setAttribute('errors', $executionResponse['errors']);
$execution->setAttribute('responseStatusCode', $executionResponse['statusCode']);
$execution->setAttribute('responseHeaders', $headersFiltered);
+1
View File
@@ -143,6 +143,7 @@ const APP_AUTH_TYPE_KEY = 'Key';
const APP_AUTH_TYPE_ADMIN = 'Admin';
// Response related
const MAX_OUTPUT_CHUNK_SIZE = 10 * 1024 * 1024; // 10MB
const APP_FUNCTION_LOG_LENGTH_LIMIT = 1000000;
// Function headers
const FUNCTION_ALLOWLIST_HEADERS_REQUEST = ['content-type', 'agent', 'content-length', 'host'];
const FUNCTION_ALLOWLIST_HEADERS_RESPONSE = ['content-type', 'content-length'];
@@ -423,12 +423,22 @@ class Create extends Base
}
}
$maxLogLength = APP_FUNCTION_LOG_LENGTH_LIMIT;
$logs = $executionResponse['logs'] ?? '';
if (\is_string($logs) && \strlen($logs) > $maxLogLength) {
$warningMessage = "\n[WARNING] Logs truncated. The output exceeded {$maxLogLength} characters.";
$warningLength = \strlen($warningMessage);
$maxContentLength = $maxLogLength - $warningLength;
$logs = \substr($logs, 0, $maxContentLength) . $warningMessage;
}
/** Update execution status */
$status = $executionResponse['statusCode'] >= 500 ? 'failed' : 'completed';
$execution->setAttribute('status', $status);
$execution->setAttribute('responseStatusCode', $executionResponse['statusCode']);
$execution->setAttribute('responseHeaders', $headersFiltered);
$execution->setAttribute('logs', $executionResponse['logs']);
$execution->setAttribute('logs', $logs);
$execution->setAttribute('errors', $executionResponse['errors']);
$execution->setAttribute('duration', $executionResponse['duration']);
} catch (\Throwable $th) {
+11 -1
View File
@@ -551,11 +551,21 @@ class Functions extends Action
}
/** Update execution status */
$maxLogLength = APP_FUNCTION_LOG_LENGTH_LIMIT;
$logs = $executionResponse['logs'] ?? '';
if (\is_string($logs) && \strlen($logs) > $maxLogLength) {
$warningMessage = "\n[WARNING] Logs truncated. The output exceeded {$maxLogLength} characters.";
$warningLength = \strlen($warningMessage);
$maxContentLength = $maxLogLength - $warningLength;
$logs = \substr($logs, 0, $maxContentLength) . $warningMessage;
}
$execution
->setAttribute('status', $status)
->setAttribute('responseStatusCode', $executionResponse['statusCode'])
->setAttribute('responseHeaders', $headersFiltered)
->setAttribute('logs', $executionResponse['logs'])
->setAttribute('logs', $logs)
->setAttribute('errors', $executionResponse['errors'])
->setAttribute('duration', $executionResponse['duration']);
} catch (\Throwable $th) {
@@ -2282,4 +2282,34 @@ class FunctionsCustomServerTest extends Scope
$this->cleanupFunction($functionId);
}
public function testLogTruncation(): void
{
$functionId = $this->setupFunction([
'functionId' => ID::unique(),
'name' => 'Test Log Truncation',
'runtime' => 'node-22',
'entrypoint' => 'index.js',
'timeout' => 15,
]);
$this->setupDeployment($functionId, [
'code' => $this->packageFunction('log-truncation'),
'activate' => true
]);
$execution = $this->createExecution($functionId, [
'async' => 'false'
]);
$this->assertEquals(201, $execution['headers']['status-code']);
$this->assertEquals(200, $execution['body']['responseStatusCode']);
// Verify logs are truncated and warning message is present
$logs = $execution['body']['logs'];
$this->assertLessThanOrEqual(APP_FUNCTION_LOG_LENGTH_LIMIT, strlen($logs));
$this->assertStringContainsString('[WARNING] Logs truncated', $logs);
$this->cleanupFunction($functionId);
}
}
@@ -0,0 +1,13 @@
module.exports = async(context) => {
// Create a string that is 1000001 characters long (exceeds the 1000000 limit)
const longString = 'a'.repeat(1000001);
context.log(longString);
return context.res.json({
motto: 'Build like a team of hundreds_',
learn: 'https://appwrite.io/docs',
connect: 'https://appwrite.io/discord',
getInspired: 'https://builtwith.appwrite.io',
});
};