gboudreau/Greyhole

View on GitHub
includes/CLI/DebugCliRunner.php

Summary

Maintainability
A
3 hrs
Test Coverage
<?php
/*
Copyright 2009-2020 Guillaume Boudreau

This file is part of Greyhole.

Greyhole is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Greyhole 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with Greyhole.  If not, see <http://www.gnu.org/licenses/>.
*/

require_once('includes/CLI/AbstractAnonymousCliRunner.php');

class DebugCliRunner extends AbstractAnonymousCliRunner {
    public function run() {
        if (!isset($this->options['cmd_param'])) {
            $this->log("Please specify a file to debug.");
            $this->finish(1);
        }
        $filename = $this->options['cmd_param'];

        if (!string_contains($filename, '/')) {
            $filename = "/$filename";
        }

        $this->log("Debugging file operations for file named \"$filename\"");
        $this->log();

        list($to_grep, $debug_tasks) = $this->getDBLogs($filename);
        $this->getAppLogs($to_grep);
        $this->getFilesystemDetails($debug_tasks);
    }

    private function getDBLogs($filename) {
        $this->log("From DB");
        $this->log("=======");

        $query = "SELECT id, action, share, full_path, additional_info, event_date FROM tasks_completed WHERE full_path LIKE :filename ORDER BY id";
        $debug_tasks = DB::getAll($query, array('filename' => "%$filename%"), 'id');

        // Renames
        $query = "SELECT id, action, share, full_path, additional_info, event_date FROM tasks_completed WHERE additional_info LIKE :filename ORDER BY id";
        $params = array('filename' => "%$filename%");
        while (TRUE) {
            $rows = DB::getAll($query, $params);
            foreach ($rows as $row) {
                $debug_tasks[$row->id] = $row;
                $query = "SELECT id, action, share, full_path, additional_info, event_date FROM tasks_completed WHERE additional_info = :full_path ORDER BY id";
                $params = array('full_path' => $row->full_path);
            }

            // Is there more?
            $new_query = preg_replace('/SELECT .* FROM/i', 'SELECT COUNT(*) FROM', $query);
            $count = DB::getFirstValue($new_query, $params);
            if ($count == 0) {
                break;
            }
        }

        ksort($debug_tasks);
        $to_grep = array();
        foreach ($debug_tasks as $task) {
            $this->log("[$task->event_date] Task ID $task->id: $task->action $task->share/$task->full_path" . ($task->action == 'rename' ? " -> $task->share/$task->additional_info" : ''));
            $to_grep["$task->share/$task->full_path"] = 1;
            if ($task->action == 'rename') {
                $to_grep["$task->share/$task->additional_info"] = 1;
            }
        }
        if (empty($to_grep)) {
            $to_grep[$filename] = 1;
            if (string_contains($filename, '/')) {
                $share = trim(mb_substr($filename, 0, mb_strpos(mb_substr($filename, 1), '/')+1), '/');
                $full_path = trim(mb_substr($filename, mb_strpos(mb_substr($filename, 1), '/')+1), '/');
                $debug_tasks[] = (object) array('share' => $share, 'full_path' => $full_path);
            }
        }

        return array($to_grep, $debug_tasks);
    }

    private function getAppLogs($to_grep) {
        $this->log();
        $this->log("From logs");
        $this->log("=========");
        $to_grep = array_keys($to_grep);
        $to_grep = implode("|", $to_grep);
        $commands = array();
        $commands[] = "zgrep -h -E -B 1 -A 2 -h " . escapeshellarg($to_grep) . " " . Config::get(CONFIG_GREYHOLE_LOG_FILE) . "*.gz";
        $commands[] = "grep -h -E -B 1 -A 2 -h " . escapeshellarg($to_grep) . " " . escapeshellarg(Config::get(CONFIG_GREYHOLE_LOG_FILE));
        foreach ($commands as $command) {
            exec($command, $result);
        }

        $result2 = array();
        $i = 0;
        foreach ($result as $rline) {
            if ($rline == '--') { continue; }
            $date_time = substr($rline, 0, 15);
            $timestamp = strtotime($date_time);
            $result2[$timestamp.sprintf("%04d", $i++)] = $rline;
        }
        ksort($result2);
        $this->log(implode("\n", $result2));
    }

    private function getFilesystemDetails($debug_tasks) {
        $this->log();
        $this->log("From filesystem");
        $this->log("===============");

        $last_task = array_pop($debug_tasks);
        $share = $last_task->share;
        $full_path = $last_task->full_path;
        $this->log("Landing Zone:");
        passthru("ls -l " . escapeshellarg(get_share_landing_zone($share) . "/" . $full_path));

        $this->log();
        $this->log("Metadata store:");
        foreach (Config::storagePoolDrives() as $sp_drive) {
            $metastore = clean_dir("$sp_drive/" . Metastores::METASTORE_DIR);
            if (file_exists("$metastore/$share/$full_path")) {
                passthru("ls -l " . escapeshellarg("$metastore/$share/$full_path"));
                $data = unserialize(file_get_contents("$metastore/$share/$full_path"));
                $this->log(json_pretty_print($data));
            }
        }

        $this->log();
        $this->log("File copies:");
        foreach (Config::storagePoolDrives() as $sp_drive) {
            if (file_exists("$sp_drive/$share/$full_path")) {
                $this->logn("  "); passthru("ls -l " . escapeshellarg("$sp_drive/$share/$full_path"));
            }
        }
    }
}

?>