public function exception(Throwable $error, $extra = [])
    {
        // We need to build a variety of pieces so we can supply information at five different verbosity levels:
        $messages   = $error->getMessage();
        $traces     = $error->getTrace();
        $serverInfo = $this->getServerInfo();
        $backtrace  = [];

        if (is_array($traces)) {
            foreach ($traces as $line) {
                /** @noinspection UnSafeIsSetOverArrayInspection */
                if (!isset($line['file'])) {
                    $line['file'] = 'unlisted file';
                }

                /** @noinspection UnSafeIsSetOverArrayInspection */
                if (!isset($line['line'])) {
                    $line['line'] = 'unlisted';
                }

                $backtrace[] = $line['file'];
                $backtrace[] = 'line::' . $line['line'];

                /** @noinspection UnSafeIsSetOverArrayInspection */
                if (isset($line['class'])) {
                    $backtrace[] = sprintf('%s::%s', $line['class'], $line['function']);
                }

                if (!empty($line['args'])) {
                    /** @var array $lineArgs */
                    $lineArgs = $line['args'];
                    $args     = [];

                    foreach ($lineArgs as $i => $arg) {
                        $args[] = $i . ' ->' . $this->typeToString($arg);
                    }

                    $backtrace[] = 'Args::' . implode(', ', $args);
                } else {
                    $backtrace[] = 'Args::None';
                }

                $backtrace[] = '';
            }
        }

        $backtrace = implode("\n", $backtrace);

        $errorDetails = [
            1 => $messages,
            2 => $messages . $serverInfo,
            3 => $messages . $serverInfo . $backtrace
        ];

        $this->log(self::ERR, $errorDetails, $extra);

        return $this;
    }