From d7e624a7d327524b9d8a5348b1f12d1ae57151ce Mon Sep 17 00:00:00 2001
From: Demian Katz <demian.katz@villanova.edu>
Date: Mon, 17 Sep 2012 15:56:41 -0400
Subject: [PATCH] Added code to capture exceptions to the log.

---
 module/VuFind/src/VuFind/Bootstrap.php  | 18 ++++-
 module/VuFind/src/VuFind/Log/Logger.php | 95 +++++++++++++++++++++++++
 2 files changed, 110 insertions(+), 3 deletions(-)

diff --git a/module/VuFind/src/VuFind/Bootstrap.php b/module/VuFind/src/VuFind/Bootstrap.php
index c3720110bb0..13376f31fd6 100644
--- a/module/VuFind/src/VuFind/Bootstrap.php
+++ b/module/VuFind/src/VuFind/Bootstrap.php
@@ -327,9 +327,21 @@ class Bootstrap
      *
      * @return void
      */
-    protected function initLog()
+    protected function initErrorLogging()
     {
-        // TODO: We need to figure out how to capture exceptions to the log -- the
-        // logic found in 2.0alpha's ErrorController needs a new home in 2.0beta.
+        $callback = function($event) {
+            $sm = $event->getApplication()->getServiceManager();
+            if ($sm->has('Logger')) {
+                $log = $sm->get('Logger');
+                if (is_callable(array($log, 'logException'))) {
+                    $exception = $event->getParam('exception');
+                    $server = $event->getRequest()->getServer();
+                    if (!empty($exception)) {
+                        $log->logException($exception, $server);
+                    }
+                }
+            }
+        };
+        $this->events->attach('dispatch.error', $callback);
     }
 }
\ No newline at end of file
diff --git a/module/VuFind/src/VuFind/Log/Logger.php b/module/VuFind/src/VuFind/Log/Logger.php
index c3b3f220fca..bdd8ba1ff5e 100644
--- a/module/VuFind/src/VuFind/Log/Logger.php
+++ b/module/VuFind/src/VuFind/Log/Logger.php
@@ -251,4 +251,99 @@ class Logger extends BaseLogger implements ServiceLocatorAwareInterface
     {
         return $this->serviceLocator;
     }
+
+    /**
+     * Add a message as a log entry
+     *
+     * @param int               $priority Priority
+     * @param mixed             $message  Message
+     * @param array|Traversable $extra    Extras
+     *
+     * @return Logger
+     */
+    public function log($priority, $message, $extra = array())
+    {
+        // Special case to handle arrays of messages (for multi-verbosity-level
+        // logging, not supported by base class):
+        if (is_array($message)) {
+            $timestamp = new \DateTime();
+            foreach ($this->writers->toArray() as $writer) {
+                $writer->write(array(
+                    'timestamp'    => $timestamp,
+                    'priority'     => (int) $priority,
+                    'priorityName' => $this->priorities[$priority],
+                    'message'      => $message,
+                    'extra'        => $extra
+                ));
+            }
+            return $this;
+        }
+        return parent::log($priority, $message, $extra);
+    }
+
+    /**
+     * Log an exception triggered by ZF2 for administrative purposes.
+     *
+     * @param \Exception              $error  Exception to log
+     * @param \Zend\Stdlib\Parameters $server Server metadata
+     *
+     * @return void
+     */
+    public function logException($error, $server)
+    {
+        // We need to build a variety of pieces so we can supply
+        // information at five different verbosity levels:
+        $baseError = $error->getMessage();
+        $referer = $server->get('HTTP_REFERER', 'none');
+        $basicServer
+            = '(Server: IP = ' . $server->get('REMOTE_ADDR') . ', '
+            . 'Referer = ' . $referer . ', '
+            . 'User Agent = '
+            . $server->get('HTTP_USER_AGENT') . ', '
+            . 'Request URI = '
+            . $server->get('REQUEST_URI') . ')';
+        $detailedServer = "\nServer Context:\n"
+            . print_r($server->toArray(), true);
+        $basicBacktrace = $detailedBacktrace = "\nBacktrace:\n";
+        if (is_array($error->getTrace())) {
+            foreach ($error->getTrace() as $line) {
+                if (!isset($line['file'])) {
+                    $line['file'] = 'unlisted file';
+                }
+                if (!isset($line['line'])) {
+                    $line['line'] = 'unlisted';
+                }
+                $basicBacktraceLine = $detailedBacktraceLine = $line['file'] .
+                    ' line ' . $line['line'] . ' - ' .
+                    (isset($line['class'])? 'class = '.$line['class'].', ' : '')
+                    . 'function = ' . $line['function'];
+                $basicBacktrace .= "{$basicBacktraceLine}\n";
+                if (!empty($line['args'])) {
+                    $args = array();
+                    foreach ($line['args'] as $i => $arg) {
+                        $val = is_object($arg)
+                            ? get_class($arg) . ' Object'
+                            : is_array($arg)
+                                ? count($arg) . '-element Array'
+                                : $arg;
+                        $args[] = $i . ' = ' . $val;
+                    }
+                    $detailedBacktraceLine .= ', args: ' . implode(', ', $args);
+                } else {
+                    $detailedBacktraceLine .= ', args: none.';
+                }
+                $detailedBacktrace .= "{$detailedBacktraceLine}\n";
+            }
+        }
+
+        $errorDetails = array(
+            1 => $baseError,
+            2 => $baseError . $basicServer,
+            3 => $baseError . $basicServer . $basicBacktrace,
+            4 => $baseError . $detailedServer . $basicBacktrace,
+            5 => $baseError . $detailedServer . $detailedBacktrace
+        );
+
+        $this->log(BaseLogger::CRIT, $errorDetails);
+    }
 }
-- 
GitLab