diff --git a/bin/analyzelogs.php b/bin/analyzelogs.php index 64b7cc1..6dc5ab0 100755 --- a/bin/analyzelogs.php +++ b/bin/analyzelogs.php @@ -1,142 +1,149 @@ #!/usr/bin/env php | | | | This program is free software: you can redistribute it and/or modify | | it under the terms of the GNU Affero General Public License as published | | by the Free Software Foundation, either version 3 of the License, or | | (at your option) any later version. | | | | This program is distributed in the hope that it will be useful, | | but WITHOUT ANY WARRANTY; without even the implied warranty of | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | | GNU Affero General Public License for more details. | | | | You should have received a copy of the GNU Affero General Public License | | along with this program. If not, see | +--------------------------------------------------------------------------+ | Author: Christian Mollekopf | +--------------------------------------------------------------------------+ */ define('RCUBE_INSTALL_PATH', realpath(dirname(__FILE__) . '/../') . '/'); // Define include path $include_path = RCUBE_INSTALL_PATH . 'lib' . PATH_SEPARATOR; $include_path .= RCUBE_INSTALL_PATH . 'lib/ext' . PATH_SEPARATOR; $include_path .= ini_get('include_path'); set_include_path($include_path); require_once "Syncroton/Command/ICommand.php"; require_once "Syncroton/Command/Wbxml.php"; require_once "Syncroton/Command/Sync.php"; require_once "Syncroton/Command/Ping.php"; require_once "Syncroton/Command/MoveItems.php"; +require_once "Syncroton/Command/FolderSync.php"; $filename = $argv[1]; $content = file_get_contents($filename); // Split up the log files into chunks that hopefully match the commands $parts = preg_split("/\[.*\]: " . preg_quote("[DEBUG] Syncroton_Server::handle::65 REQUEST METHOD: POST", '/') . "/", $content, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE); function getStatusConstants($classname) { $reflect = new ReflectionClass($classname); $result = $reflect->getConstants(); $result = array_filter($result, function ($val) { return str_starts_with($val, "STATUS_"); }, ARRAY_FILTER_USE_KEY); $result = array_flip($result); return $result; } function explainStatus($command, $status) { + if (!$status) { + return "none"; + } switch ($command) { case "Ping": $result = getStatusConstants("Syncroton_Command_Ping"); return $result[$status] ?? "Unknown"; case "Sync": $result = getStatusConstants("Syncroton_Command_Sync"); return $result[$status] ?? "Unknown"; case "MoveItems": $result = getStatusConstants("Syncroton_Command_MoveItems"); return $result[$status] ?? "Unknown"; + case "FolderSync": + $result = getStatusConstants("Syncroton_Command_FolderSync"); + return $result[$status] ?? "Unknown"; } - return "Unkonwn"; + return "Unknown command"; } foreach ($parts as $part) { preg_match('/\[(.*)\]: /', $part, $matches); $timestamp = $matches[1]; preg_match('/\[command\] => (.*)/', $part, $matches); $command = $matches[1]; preg_match('/\(.*)\<\/Status\>/', $part, $matches); $status = $matches[1] ?? null; $statusExplained = explainStatus($command, $status); print(" Command: " . str_pad($command, 10) . str_pad("\tStatus: $status ($statusExplained)", 45) . "\tTimestamp: $timestamp\n"); if ($command == "Sync") { // Find collections within this sync // [25-Sep-2024 09:16:35.347730]: [INFO] Syncroton_Command_Sync::handle::221 SyncKey is 7301 Class: Email CollectionId: 38b950ebd62cd9a66929c89615d0fc04 if (preg_match_all('/SyncKey is (.*) Class: (.*) CollectionId: (.*)/', $part, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) { foreach ($matches as $set) { $offset = $set[0][1]; $collectionId = $set[3][0]; $class = $set[2][0]; $synckey = $set[1][0]; print(str_pad(" Collection: $collectionId ($class)", 58) . "\tSyncKey: $synckey\n"); //Find the offset for this collections messages if (preg_match("/Processing $collectionId\.\.\./", $part, $match, PREG_OFFSET_CAPTURE, $offset)) { // print_r($match); $offset = $match[0][1] ?? null; //Find the actual changes if ($offset && preg_match('/found \(added\/changed\/deleted\) (.*)\/(.*)\/(.*) entries for sync from server to client/', $part, $changesMatch, PREG_OFFSET_CAPTURE, $offset)) { // If the offset is too large we are looking at the next collection. if ($changesMatch[0][1] - $offset < 200) { print(" " . $changesMatch[0][0] . "\n"); } } } //TODO We could figure out what the diff per collection was in terms of synckey to the last sync //TODO We could figure out what we actually return in the response compared to the detected changeset //TODO Warn if a collection is repeatedly synced with the same synckey, but changes are detected. It may be stuck in a sync loop. } } // Detect entries that are being added from the client if (preg_match_all('/found (.*) entries to be added on server/', $part, $matches)) { foreach ($matches[0] ?? [] as $match) { print(" " . $match . "\n"); } } if (preg_match_all('/found (.*) entries to be updated on server/', $part, $matches)) { foreach ($matches[0] ?? [] as $match) { print(" " . $match . "\n"); } } if (preg_match_all('/found (.*) entries to be deleted on server/', $part, $matches)) { foreach ($matches[0] ?? [] as $match) { print(" " . $match . "\n"); } } } //TODO on Sync: //* number of Add/Change/Remove from client and from server //* Synckey //* list involved folders //TODO on Sync: //* Reason for interruption }