Index: feeds.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feeds/feeds.install,v
retrieving revision 1.13.2.1
diff -u -p -r1.13.2.1 feeds.install
--- feeds.install	25 Sep 2010 16:07:50 -0000	1.13.2.1
+++ feeds.install	28 Nov 2010 03:18:44 -0000
@@ -230,6 +230,76 @@ function feeds_schema() {
       'timestamp' => array('timestamp'),
     ),
   );
+  $schema['feeds_log'] = array(
+    'description' => 'Table that contains logs of feeds events.',
+    'fields' => array(
+      'flid' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'Primary Key: Unique feeds event ID.',
+      ),
+      'id' => array(
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The id of the importer that logged the event.',
+      ),
+      'feed_nid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'Node id of the source, if available.',
+      ),
+      'log_time' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Unix timestamp of when event occurred.',
+      ),
+      'request_time' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Unix timestamp of the request when the event occurred.',
+      ),
+      'type' => array(
+        'type' => 'varchar',
+        'length' => 64,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'Type of log message, for example "feeds_import"."',
+      ),
+      'message' => array(
+        'type' => 'text',
+        'not null' => TRUE,
+        'size' => 'big',
+        'description' => 'Text of log message to be passed into the t() function.',
+      ),
+      'variables' => array(
+        'type' => 'blob',
+        'not null' => TRUE,
+        'size' => 'big',
+        'description' => 'Serialized array of variables that match the message string and that is passed into the t() function.',
+      ),
+      'severity' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+        'description' => 'The severity level of the event; ranges from 0 (Emergency) to 7 (Debug)',
+      ),
+    ),
+    'primary key' => array('flid'),
+    'indexes' => array(
+      'id' => array('id'),
+      'id_feed_nid' => array('id', 'feed_nid'),
+      'request_time' => array('request_time'),
+      'log_time' => array('log_time'),
+      'type' => array('type'),
+    ),
+  );
   return $schema;
 }
 
@@ -567,3 +637,80 @@ function feeds_update_6013() {
   variable_set('feeds_reschedule', TRUE);
   return array();
 }
+
+/**
+ * Add feeds_log table.
+ */
+function feeds_update_6014() {
+  $schema = array(
+    'description' => 'Table that contains logs of feeds events.',
+    'fields' => array(
+      'flid' => array(
+        'type' => 'serial',
+        'not null' => TRUE,
+        'description' => 'Primary Key: Unique feeds event ID.',
+      ),
+      'id' => array(
+        'type' => 'varchar',
+        'length' => 128,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'The id of the importer that logged the event.',
+      ),
+      'feed_nid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'description' => 'Node id of the source, if available.',
+      ),
+      'log_time' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Unix timestamp of when event occurred.',
+      ),
+      'request_time' => array(
+        'type' => 'int',
+        'not null' => TRUE,
+        'default' => 0,
+        'description' => 'Unix timestamp of the request when the event occurred.',
+      ),
+      'type' => array(
+        'type' => 'varchar',
+        'length' => 64,
+        'not null' => TRUE,
+        'default' => '',
+        'description' => 'Type of log message, for example "feeds_import"."',
+      ),
+      'message' => array(
+        'type' => 'text',
+        'not null' => TRUE,
+        'size' => 'big',
+        'description' => 'Text of log message to be passed into the t() function.',
+      ),
+      'variables' => array(
+        'type' => 'blob',
+        'not null' => TRUE,
+        'size' => 'big',
+        'description' => 'Serialized array of variables that match the message string and that is passed into the t() function.',
+      ),
+      'severity' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+        'size' => 'tiny',
+        'description' => 'The severity level of the event; ranges from 0 (Emergency) to 7 (Debug)',
+      ),
+    ),
+    'primary key' => array('flid'),
+    'indexes' => array(
+      'id' => array('id'),
+      'id_feed_nid' => array('id', 'feed_nid'),
+      'request_time' => array('request_time'),
+      'log_time' => array('log_time'),
+      'type' => array('type'),
+    ),
+  );
+  db_create_table($ret, 'feeds_log', $schema);
+}
Index: feeds.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feeds/feeds.module,v
retrieving revision 1.55.2.3
diff -u -p -r1.55.2.3 feeds.module
--- feeds.module	28 Oct 2010 19:58:22 -0000	1.55.2.3
+++ feeds.module	28 Nov 2010 03:18:45 -0000
@@ -38,6 +38,7 @@ function feeds_cron() {
     feeds_reschedule(FALSE);
     return;
   }
+  db_query('DELETE FROM {feeds_log} WHERE request_time < %d', $_SERVER['REQUEST_TIME'] - 604800);
 }
 
 /**
@@ -68,7 +69,7 @@ function feeds_source_import($job) {
   }
   catch (FeedsNotExistingException $e) {}
   catch (Exception $e) {
-    watchdog('feeds_source_import()', $e->getMessage(), array(), WATCHDOG_ERROR);
+    $source->log('import', $e->getMessage(), array(), WATCHDOG_ERROR);
   }
   $source->schedule();
 }
@@ -151,65 +152,69 @@ function feeds_forms() {
  * Implementation of hook_menu().
  */
 function feeds_menu() {
-  // Register a callback for all feed configurations that are not attached to a content type.
   $items = array();
+  $items['import'] = array(
+    'title' => 'Import',
+    'page callback' => 'feeds_page',
+    'access callback' => 'feeds_page_access',
+    'file' => 'feeds.pages.inc',
+  );
+  $items['import/%'] = array(
+    'title callback' => 'feeds_importer_title',
+    'title arguments' => array(1),
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('feeds_import_form', 1),
+    'access callback' => 'feeds_access',
+    'access arguments' => array('import', 1),
+    'file' => 'feeds.pages.inc',
+  );
+  $items['import/%/import'] = array(
+    'title' => 'Import',
+    'type' => MENU_DEFAULT_LOCAL_TASK,
+    'weight' => -10,
+  );
+  $items['import/%/delete-items'] = array(
+    'title' => 'Delete items',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('feeds_delete_tab_form', 1),
+    'access callback' => 'feeds_access',
+    'access arguments' => array('clear', 1),
+    'file' => 'feeds.pages.inc',
+    'type' => MENU_LOCAL_TASK,
+  );
+  $items['import/%/template'] = array(
+    'page callback' => 'feeds_importer_template',
+    'page arguments' => array(1),
+    'access callback' => 'feeds_access',
+    'access arguments' => array('import', 1),
+    'file' => 'feeds.pages.inc',
+    'type' => MENU_CALLBACK,
+  );
+  $items['node/%node/import'] = array(
+    'title' => 'Import',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('feeds_import_tab_form', 1),
+    'access callback' => 'feeds_access',
+    'access arguments' => array('import', 1),
+    'file' => 'feeds.pages.inc',
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 10,
+  );
+  $items['node/%node/delete-items'] = array(
+    'title' => 'Delete items',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('feeds_delete_tab_form', NULL, 1),
+    'access callback' => 'feeds_access',
+    'access arguments' => array('clear', 1),
+    'file' => 'feeds.pages.inc',
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 11,
+  );
+  // @todo Eliminate this step and thus eliminate clearing menu cache when
+  // manipulating importers.
   foreach (feeds_importer_load_all() as $importer) {
-    if (empty($importer->config['content_type'])) {
-      $items['import/'. $importer->id] = array(
-        'title' => $importer->config['name'],
-        'page callback' => 'drupal_get_form',
-        'page arguments' => array('feeds_import_form', 1),
-        'access callback' => 'feeds_access',
-        'access arguments' => array('import', $importer->id),
-        'file' => 'feeds.pages.inc',
-      );
-      $items['import/'. $importer->id .'/import'] = array(
-        'title' => 'Import',
-        'type' => MENU_DEFAULT_LOCAL_TASK,
-        'weight' => -10,
-      );
-      $items['import/'. $importer->id .'/delete-items'] = array(
-        'title' => 'Delete items',
-        'page callback' => 'drupal_get_form',
-        'page arguments' => array('feeds_delete_tab_form', 1),
-        'access callback' => 'feeds_access',
-        'access arguments' => array('clear', $importer->id),
-        'file' => 'feeds.pages.inc',
-        'type' => MENU_LOCAL_TASK,
-      );
-    }
-    else {
-      $items['node/%node/import'] = array(
-        'title' => 'Import',
-        'page callback' => 'drupal_get_form',
-        'page arguments' => array('feeds_import_tab_form', 1),
-        'access callback' => 'feeds_access',
-        'access arguments' => array('import', 1),
-        'file' => 'feeds.pages.inc',
-        'type' => MENU_LOCAL_TASK,
-        'weight' => 10,
-      );
-      $items['node/%node/delete-items'] = array(
-        'title' => 'Delete items',
-        'page callback' => 'drupal_get_form',
-        'page arguments' => array('feeds_delete_tab_form', NULL, 1),
-        'access callback' => 'feeds_access',
-        'access arguments' => array('clear', 1),
-        'file' => 'feeds.pages.inc',
-        'type' => MENU_LOCAL_TASK,
-        'weight' => 11,
-      );
-    }
     $items += $importer->fetcher->menuItem();
   }
-  if (count($items)) {
-    $items['import'] = array(
-      'title' => 'Import',
-      'page callback' => 'feeds_page',
-      'access callback' => 'feeds_page_access',
-      'file' => 'feeds.pages.inc',
-    );
-  }
   return $items;
 }
 
@@ -221,6 +226,14 @@ function feeds_importer_load($id) {
 }
 
 /**
+ * Title callback.
+ */
+function feeds_importer_title($id) {
+  $importer = feeds_importer($id);
+  return $importer->config['name'];
+}
+
+/**
  * Implementation of hook_theme().
  */
 function feeds_theme() {
@@ -272,6 +285,15 @@ function feeds_page_access() {
 }
 
 /**
+ * Implements hook_exit().
+ */
+function feeds_exit() {
+  if (ctools_static('feeds_log_error', FALSE)) {
+    watchdog('feeds', 'Feeds reported errors, visit the Feeds log for details.', array(), WATCHDOG_ERROR, 'admin/reports/dblog/feeds');
+  }
+}
+
+/**
  * Implementation of hook_views_api().
  */
 function feeds_views_api() {
@@ -384,14 +406,24 @@ function feeds_nodeapi(&$node, $op, $for
         }
         $node_feeds = NULL;
         break;
-      case 'delete':
-        $source = feeds_source($importer_id, $node->nid);
-        if ($source->importer->processor->config['delete_with_source']) {
-          feeds_batch_set(t('Deleting'), 'clear', $importer_id, $node->nid);
-        }
-        // Remove attached source.
-        $source->delete();
-        break;
+    }
+  }
+
+  if ($op == 'delete') {
+   // Make sure we don't leave any orphans behind: If feeds_get_importer_id
+   // didn't find the id check manually in case the importer was deleted.
+    if (!$importer_id) {
+      $query = db_query('SELECT id FROM {feeds_source} WHERE feed_nid = %d', $node->nid);
+      $importer_id = db_result($query);
+    }
+
+    if ($importer_id) {
+      $source = feeds_source($importer_id, $node->nid);
+      if ($source->importer->processor->config['delete_with_source']) {
+        feeds_batch_set(t('Deleting'), 'clear', $importer_id, $node->nid);
+      }
+      // Remove attached source.
+      $source->delete();
     }
   }
 }
@@ -649,6 +681,30 @@ function feeds_dbg($msg) {
 }
 
 /**
+ * Writes to feeds log.
+ */
+function feeds_log($importer_id, $feed_nid, $type, $message, $variables = array(), $severity = WATCHDOG_NOTICE) {
+  if ($severity < WATCHDOG_NOTICE) {
+    $error = &ctools_static('feeds_log_error', FALSE);
+    $error = TRUE;
+  }
+  db_query(
+    "INSERT INTO {feeds_log}
+    (id, feed_nid, log_time, request_time, type, message, variables, severity)
+    VALUES
+    ('%s', %d, %d, %d, '%s', '%s', '%s', %d)",
+    $importer_id,
+    $feed_nid,
+    time(),
+    $_SERVER['REQUEST_TIME'],
+    $type,
+    $message,
+    serialize($variables),
+    $severity
+  );
+}
+
+/**
  * @}
  */
 
Index: includes/FeedsSource.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feeds/includes/FeedsSource.inc,v
retrieving revision 1.21.2.1
diff -u -p -r1.21.2.1 FeedsSource.inc
--- includes/FeedsSource.inc	26 Sep 2010 17:39:45 -0000	1.21.2.1
+++ includes/FeedsSource.inc	28 Nov 2010 03:18:46 -0000
@@ -358,4 +358,11 @@ class FeedsSource extends FeedsConfigura
       }
     }
   }
+
+  /**
+   * Writes to feeds log.
+   */
+  public function log($type, $message, $variables = array(), $severity = WATCHDOG_NOTICE) {
+    feeds_log($this->id, $this->feed_nid, $type, $message, $variables, $severity);
+  }
 }
Index: plugins/FeedsNodeProcessor.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feeds/plugins/FeedsNodeProcessor.inc,v
retrieving revision 1.51.2.2
diff -u -p -r1.51.2.2 FeedsNodeProcessor.inc
--- plugins/FeedsNodeProcessor.inc	25 Oct 2010 22:43:03 -0000	1.51.2.2
+++ plugins/FeedsNodeProcessor.inc	28 Nov 2010 03:18:46 -0000
@@ -57,7 +57,12 @@ class FeedsNodeProcessor extends FeedsPr
         }
         catch (Exception $e) {
           drupal_set_message($e->getMessage(), 'warning');
-          watchdog('feeds', $e->getMessage(), array(), WATCHDOG_WARNING);
+          $message = $e->getMessage();
+          $message .= '<h3>Original item</h3>';
+          $message .= '<pre>' . var_export($item, TRUE) . '</pre>';
+          $message .= '<h3>Node</h3>';
+          $message .= '<pre>' . var_export($node, TRUE) . '</pre>';
+          $source->log('import', $message, array(), WATCHDOG_ERROR);
         }
       }
 
Index: views/feeds.views.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/feeds/views/feeds.views.inc,v
retrieving revision 1.3
diff -u -p -r1.3 feeds.views.inc
--- views/feeds.views.inc	11 Jul 2010 16:57:02 -0000	1.3
+++ views/feeds.views.inc	28 Nov 2010 03:18:46 -0000
@@ -171,6 +171,142 @@ function feeds_views_data() {
       'help' => t('Argument on a Feeds Item\'s import date field.'),
     ),
   );
+  /**
+   * Expose feeds_log table to views.
+   */
+  $data['feeds_log']['table'] = array(
+    'group' => 'Feeds log',
+    'base' => array(
+      'field' => array('flid'),
+      'title' => 'Feeds log',
+      'help' => 'Logs events during importing, clearing, expiry.',
+    ),
+  );
+  $data['feeds_log']['id'] = array(
+    'title' => 'Importer id',
+    'help' => 'The id of an importer.',
+    'field' => array(
+      'handler' => 'feeds_views_handler_field',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_string',
+      'allow empty' => TRUE,
+      'help' => 'Filter on an importer id.',
+    ),
+    'argument' => array(
+      'handler' => 'feeds_views_handler_argument_importer_id',
+      'help' => 'Filter on an importer id.',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+      'help' => 'Sort by importer id.',
+    ),
+    'relationship' => array(
+      'title' => t('Importer'),
+      'help' => t('Relate a log entry to its importer if available.'),
+      'label' => t('Importer'),
+      'base' => 'feeds_importer',
+      'base field' => 'id',
+    ),
+  );
+  $data['feeds_log']['importer_name'] = array(
+    'real field' => 'id',
+    'title' => 'Importer name',
+    'help' => 'The human readable name of an importer.',
+    'field' => array(
+      'handler' => 'feeds_views_handler_field_importer_name',
+    ),
+  );
+  $data['feeds_log']['feed_nid'] = array(
+    'title' => 'Feed node id',
+    'help' => 'Contains the node id of a feed node if the feed\'s configuration is attached to a content type, otherwise contains 0.',
+    'field' => array(
+      'handler' => 'feeds_views_handler_field_numeric',
+      'click sortable' => TRUE,
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_numeric',
+      'allow empty' => TRUE,
+      'help' => 'Filter on a Feeds Source\'s feed_nid field.',
+    ),
+    'argument' => array(
+      'handler' => 'views_handler_argument_numeric',
+      'numeric' => TRUE,
+      'validate type' => 'nid',
+      'help' => 'Argument on a Feeds Source\'s feed_nid field.',
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort',
+      'help' => 'Sort Feeds Source\'s feed_nid field.',
+    ),
+    'relationship' => array(
+      'title' => t('Feed node'),
+      'help' => t('Relate a log entry to its feed node if available.'),
+      'label' => t('Feed node'),
+      'base' => 'node',
+      'base field' => 'nid',
+    ),
+  );
+  $data['feeds_log']['log_time'] = array(
+    'title' => t('Log time'),
+    'help' => t('The time of the event.'),
+    'field' => array(
+      'handler' => 'views_handler_field_date',
+      'click sortable' => TRUE,
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort_date',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_date',
+    ),
+  );
+  $data['feeds_log']['request_time'] = array(
+    'title' => t('Request time'),
+    'help' => t('The time of the page request of an event.'),
+    'field' => array(
+      'handler' => 'views_handler_field_date',
+      'click sortable' => TRUE,
+    ),
+    'sort' => array(
+      'handler' => 'views_handler_sort_date',
+    ),
+    'filter' => array(
+      'handler' => 'views_handler_filter_date',
+    ),
+  );
+  $data['feeds_log']['message'] = array(
+    'title' => 'Log message',
+    'help' => 'The message logged by the event.',
+    'field' => array(
+      'handler' => 'feeds_views_handler_field_log_message',
+      'click sortable' => FALSE,
+      'additional fields' => array(
+        'variables',
+      ),
+    ),
+  );
+  $data['feeds_log']['severity'] = array(
+    'title' => 'Severity',
+    'help' => 'The severity of the event logged.',
+    'field' => array(
+      'handler' => 'feeds_views_handler_field_severity',
+      'click sortable' => FALSE,
+    ),
+    'filter' => array(
+      'handler' => 'feeds_views_handler_filter_severity',
+      'allow empty' => TRUE,
+      'help' => 'Filter on the severity of a log message.',
+    ),
+  );
+  $data['feeds_log']['table']['join'] = array(
+    'node' => array(
+      'left_field' => 'nid',
+      'field' => 'feed_nid',
+      'type' => 'LEFT',
+    ),
+  );
   return $data;
 }
 
@@ -184,9 +320,27 @@ function feeds_views_handlers() {
     ),
     'handlers' => array(
       // field handlers
+      'feeds_views_handler_argument_importer_id' => array(
+        'parent' => 'views_handler_argument_string',
+      ),
+      'feeds_views_handler_field_importer_name' => array(
+        'parent' => 'views_handler_field',
+      ),
+      'feeds_views_handler_field_log_message' => array(
+        'parent' => 'views_handler_field',
+      ),
+      'feeds_views_handler_field_severity' => array(
+        'parent' => 'views_handler_field',
+      ),
       'feeds_views_handler_field_source' => array(
         'parent' => 'views_handler_field',
       ),
+      'feeds_views_handler_field_severity' => array(
+        'parent' => 'views_handler_field',
+      ),
+      'feeds_views_handler_filter_severity' => array(
+        'parent' => 'views_handler_filter_in_operator',
+      ),
     ),
   );
 }
Index: views/feeds.views_default.inc
===================================================================
RCS file: views/feeds.views_default.inc
diff -N views/feeds.views_default.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ views/feeds.views_default.inc	28 Nov 2010 03:18:47 -0000
@@ -0,0 +1,286 @@
+<?php
+// $Id: feeds.views_default.inc,v 1.1.2.1 2010/10/26 03:05:58 alexb Exp $
+
+/**
+ * @file
+ * Default view definitions for Feeds.
+ */
+
+/**
+ * Implementation of hook_views_default_views().
+ */
+function feeds_views_default_views() {
+  $views = array();
+
+  $view = new view;
+  $view->name = 'feeds_log';
+  $view->description = 'Feeds log displays for overview, standalone importers and feed nodes.';
+  $view->tag = 'Feeds';
+  $view->base_table = 'feeds_log';
+  $view->api_version = '3.0-alpha1';
+  $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
+
+  /* Display: Defaults */
+  $handler = $view->new_display('default', 'Defaults', 'default');
+  $handler->display->display_options['access']['type'] = 'perm';
+  $handler->display->display_options['access']['perm'] = 'administer feeds';
+  $handler->display->display_options['cache']['type'] = 'none';
+  $handler->display->display_options['query']['type'] = 'views_query';
+  $handler->display->display_options['exposed_form']['type'] = 'basic';
+  $handler->display->display_options['pager']['type'] = 'full';
+  $handler->display->display_options['pager']['options']['items_per_page'] = '50';
+  $handler->display->display_options['pager']['options']['offset'] = '0';
+  $handler->display->display_options['pager']['options']['id'] = '0';
+  $handler->display->display_options['style_plugin'] = 'table';
+  $handler->display->display_options['style_options']['columns'] = array(
+    'log_time' => 'log_time',
+    'request_time' => 'request_time',
+    'message' => 'message',
+    'severity' => 'severity',
+  );
+  $handler->display->display_options['style_options']['default'] = '-1';
+  $handler->display->display_options['style_options']['info'] = array(
+    'log_time' => array(
+      'sortable' => 0,
+      'align' => '',
+      'separator' => '',
+    ),
+    'request_time' => array(
+      'sortable' => 0,
+      'align' => '',
+      'separator' => '',
+    ),
+    'message' => array(
+      'align' => '',
+      'separator' => '',
+    ),
+    'severity' => array(
+      'align' => '',
+      'separator' => '',
+    ),
+  );
+  $handler->display->display_options['style_options']['override'] = 1;
+  $handler->display->display_options['style_options']['sticky'] = 0;
+  /* Empty text: Global: Text area */
+  $handler->display->display_options['empty']['area']['id'] = 'area';
+  $handler->display->display_options['empty']['area']['table'] = 'views';
+  $handler->display->display_options['empty']['area']['field'] = 'area';
+  $handler->display->display_options['empty']['area']['empty'] = FALSE;
+  $handler->display->display_options['empty']['area']['content'] = 'There are no log messages.';
+  $handler->display->display_options['empty']['area']['format'] = '1';
+  /* Field: Feeds log: Log time */
+  $handler->display->display_options['fields']['log_time']['id'] = 'log_time';
+  $handler->display->display_options['fields']['log_time']['table'] = 'feeds_log';
+  $handler->display->display_options['fields']['log_time']['field'] = 'log_time';
+  $handler->display->display_options['fields']['log_time']['alter']['alter_text'] = 0;
+  $handler->display->display_options['fields']['log_time']['alter']['make_link'] = 0;
+  $handler->display->display_options['fields']['log_time']['alter']['absolute'] = 0;
+  $handler->display->display_options['fields']['log_time']['alter']['trim'] = 0;
+  $handler->display->display_options['fields']['log_time']['alter']['word_boundary'] = 1;
+  $handler->display->display_options['fields']['log_time']['alter']['ellipsis'] = 1;
+  $handler->display->display_options['fields']['log_time']['alter']['strip_tags'] = 0;
+  $handler->display->display_options['fields']['log_time']['alter']['html'] = 0;
+  $handler->display->display_options['fields']['log_time']['hide_empty'] = 0;
+  $handler->display->display_options['fields']['log_time']['empty_zero'] = 0;
+  $handler->display->display_options['fields']['log_time']['date_format'] = 'custom';
+  $handler->display->display_options['fields']['log_time']['custom_date_format'] = 'Y-m-d H:i:s';
+  /* Field: Feeds log: Request time */
+  $handler->display->display_options['fields']['request_time']['id'] = 'request_time';
+  $handler->display->display_options['fields']['request_time']['table'] = 'feeds_log';
+  $handler->display->display_options['fields']['request_time']['field'] = 'request_time';
+  $handler->display->display_options['fields']['request_time']['alter']['alter_text'] = 0;
+  $handler->display->display_options['fields']['request_time']['alter']['make_link'] = 0;
+  $handler->display->display_options['fields']['request_time']['alter']['absolute'] = 0;
+  $handler->display->display_options['fields']['request_time']['alter']['trim'] = 0;
+  $handler->display->display_options['fields']['request_time']['alter']['word_boundary'] = 1;
+  $handler->display->display_options['fields']['request_time']['alter']['ellipsis'] = 1;
+  $handler->display->display_options['fields']['request_time']['alter']['strip_tags'] = 0;
+  $handler->display->display_options['fields']['request_time']['alter']['html'] = 0;
+  $handler->display->display_options['fields']['request_time']['hide_empty'] = 0;
+  $handler->display->display_options['fields']['request_time']['empty_zero'] = 0;
+  $handler->display->display_options['fields']['request_time']['date_format'] = 'custom';
+  $handler->display->display_options['fields']['request_time']['custom_date_format'] = 'Y-m-d H:i:s';
+  /* Field: Feeds log: Log message */
+  $handler->display->display_options['fields']['message']['id'] = 'message';
+  $handler->display->display_options['fields']['message']['table'] = 'feeds_log';
+  $handler->display->display_options['fields']['message']['field'] = 'message';
+  $handler->display->display_options['fields']['message']['label'] = 'Message';
+  $handler->display->display_options['fields']['message']['hide_empty'] = 0;
+  $handler->display->display_options['fields']['message']['empty_zero'] = 0;
+  /* Field: Feeds log: Severity */
+  $handler->display->display_options['fields']['severity']['id'] = 'severity';
+  $handler->display->display_options['fields']['severity']['table'] = 'feeds_log';
+  $handler->display->display_options['fields']['severity']['field'] = 'severity';
+  $handler->display->display_options['fields']['severity']['hide_empty'] = 0;
+  $handler->display->display_options['fields']['severity']['empty_zero'] = 0;
+  /* Sort criterion: Feeds log: Log time */
+  $handler->display->display_options['sorts']['log_time']['id'] = 'log_time';
+  $handler->display->display_options['sorts']['log_time']['table'] = 'feeds_log';
+  $handler->display->display_options['sorts']['log_time']['field'] = 'log_time';
+  $handler->display->display_options['sorts']['log_time']['order'] = 'DESC';
+  /* Argument: Feeds log: Importer id */
+  $handler->display->display_options['arguments']['id']['id'] = 'id';
+  $handler->display->display_options['arguments']['id']['table'] = 'feeds_log';
+  $handler->display->display_options['arguments']['id']['field'] = 'id';
+  $handler->display->display_options['arguments']['id']['default_action'] = 'empty';
+  $handler->display->display_options['arguments']['id']['style_plugin'] = 'default_summary';
+  $handler->display->display_options['arguments']['id']['default_argument_type'] = 'fixed';
+  $handler->display->display_options['arguments']['id']['validate_fail'] = 'empty';
+  $handler->display->display_options['arguments']['id']['glossary'] = 0;
+  $handler->display->display_options['arguments']['id']['limit'] = '0';
+  $handler->display->display_options['arguments']['id']['transform_dash'] = 0;
+  /* Filter: Feeds log: Feed node id */
+  $handler->display->display_options['filters']['feed_nid']['id'] = 'feed_nid';
+  $handler->display->display_options['filters']['feed_nid']['table'] = 'feeds_log';
+  $handler->display->display_options['filters']['feed_nid']['field'] = 'feed_nid';
+  $handler->display->display_options['filters']['feed_nid']['value']['value'] = '0';
+  /* Filter: Feeds log: Severity */
+  $handler->display->display_options['filters']['severity']['id'] = 'severity';
+  $handler->display->display_options['filters']['severity']['table'] = 'feeds_log';
+  $handler->display->display_options['filters']['severity']['field'] = 'severity';
+  $handler->display->display_options['filters']['severity']['exposed'] = TRUE;
+  $handler->display->display_options['filters']['severity']['expose']['operator'] = 'severity_op';
+  $handler->display->display_options['filters']['severity']['expose']['label'] = 'Severity';
+  $handler->display->display_options['filters']['severity']['expose']['use_operator'] = FALSE;
+  $handler->display->display_options['filters']['severity']['expose']['identifier'] = 'severity';
+  $handler->display->display_options['filters']['severity']['expose']['reduce'] = 0;
+
+  /* Display: Standalone importer page */
+  $handler = $view->new_display('page', 'Standalone importer page', 'page_1');
+  $handler->display->display_options['path'] = 'import/%/log';
+  $handler->display->display_options['menu']['type'] = 'tab';
+  $handler->display->display_options['menu']['title'] = 'Log';
+  $handler->display->display_options['menu']['weight'] = '0';
+
+  /* Display: Feed node page */
+  $handler = $view->new_display('page', 'Feed node page', 'page_2');
+  $handler->display->display_options['defaults']['arguments'] = FALSE;
+  /* Argument: Feeds log: Feed node id */
+  $handler->display->display_options['arguments']['feed_nid']['id'] = 'feed_nid';
+  $handler->display->display_options['arguments']['feed_nid']['table'] = 'feeds_log';
+  $handler->display->display_options['arguments']['feed_nid']['field'] = 'feed_nid';
+  $handler->display->display_options['arguments']['feed_nid']['default_action'] = 'not found';
+  $handler->display->display_options['arguments']['feed_nid']['style_plugin'] = 'default_summary';
+  $handler->display->display_options['arguments']['feed_nid']['default_argument_type'] = 'fixed';
+  $handler->display->display_options['arguments']['feed_nid']['break_phrase'] = 0;
+  $handler->display->display_options['arguments']['feed_nid']['not'] = 0;
+  $handler->display->display_options['defaults']['filters'] = FALSE;
+  /* Filter: Feeds log: Severity */
+  $handler->display->display_options['filters']['severity']['id'] = 'severity';
+  $handler->display->display_options['filters']['severity']['table'] = 'feeds_log';
+  $handler->display->display_options['filters']['severity']['field'] = 'severity';
+  $handler->display->display_options['filters']['severity']['exposed'] = TRUE;
+  $handler->display->display_options['filters']['severity']['expose']['operator'] = 'severity_op';
+  $handler->display->display_options['filters']['severity']['expose']['label'] = 'Severity';
+  $handler->display->display_options['filters']['severity']['expose']['use_operator'] = FALSE;
+  $handler->display->display_options['filters']['severity']['expose']['identifier'] = 'severity';
+  $handler->display->display_options['filters']['severity']['expose']['reduce'] = 0;
+  $handler->display->display_options['path'] = 'node/%/log';
+  $handler->display->display_options['menu']['type'] = 'tab';
+  $handler->display->display_options['menu']['title'] = 'Log';
+  $handler->display->display_options['menu']['weight'] = '12';
+
+  /* Display: All entries */
+  $handler = $view->new_display('page', 'All entries', 'page_3');
+  $handler->display->display_options['defaults']['title'] = FALSE;
+  $handler->display->display_options['title'] = 'Feeds log';
+  $handler->display->display_options['defaults']['relationships'] = FALSE;
+  /* Relationship: Feeds log: Feed node */
+  $handler->display->display_options['relationships']['feed_nid']['id'] = 'feed_nid';
+  $handler->display->display_options['relationships']['feed_nid']['table'] = 'feeds_log';
+  $handler->display->display_options['relationships']['feed_nid']['field'] = 'feed_nid';
+  $handler->display->display_options['defaults']['fields'] = FALSE;
+  /* Field: Feeds log: Log time */
+  $handler->display->display_options['fields']['log_time']['id'] = 'log_time';
+  $handler->display->display_options['fields']['log_time']['table'] = 'feeds_log';
+  $handler->display->display_options['fields']['log_time']['field'] = 'log_time';
+  $handler->display->display_options['fields']['log_time']['alter']['alter_text'] = 0;
+  $handler->display->display_options['fields']['log_time']['alter']['make_link'] = 0;
+  $handler->display->display_options['fields']['log_time']['alter']['absolute'] = 0;
+  $handler->display->display_options['fields']['log_time']['alter']['trim'] = 0;
+  $handler->display->display_options['fields']['log_time']['alter']['word_boundary'] = 1;
+  $handler->display->display_options['fields']['log_time']['alter']['ellipsis'] = 1;
+  $handler->display->display_options['fields']['log_time']['alter']['strip_tags'] = 0;
+  $handler->display->display_options['fields']['log_time']['alter']['html'] = 0;
+  $handler->display->display_options['fields']['log_time']['hide_empty'] = 0;
+  $handler->display->display_options['fields']['log_time']['empty_zero'] = 0;
+  $handler->display->display_options['fields']['log_time']['date_format'] = 'custom';
+  $handler->display->display_options['fields']['log_time']['custom_date_format'] = 'Y-m-d H:i:s';
+  /* Field: Feeds log: Request time */
+  $handler->display->display_options['fields']['request_time']['id'] = 'request_time';
+  $handler->display->display_options['fields']['request_time']['table'] = 'feeds_log';
+  $handler->display->display_options['fields']['request_time']['field'] = 'request_time';
+  $handler->display->display_options['fields']['request_time']['alter']['alter_text'] = 0;
+  $handler->display->display_options['fields']['request_time']['alter']['make_link'] = 0;
+  $handler->display->display_options['fields']['request_time']['alter']['absolute'] = 0;
+  $handler->display->display_options['fields']['request_time']['alter']['trim'] = 0;
+  $handler->display->display_options['fields']['request_time']['alter']['word_boundary'] = 1;
+  $handler->display->display_options['fields']['request_time']['alter']['ellipsis'] = 1;
+  $handler->display->display_options['fields']['request_time']['alter']['strip_tags'] = 0;
+  $handler->display->display_options['fields']['request_time']['alter']['html'] = 0;
+  $handler->display->display_options['fields']['request_time']['hide_empty'] = 0;
+  $handler->display->display_options['fields']['request_time']['empty_zero'] = 0;
+  $handler->display->display_options['fields']['request_time']['date_format'] = 'custom';
+  $handler->display->display_options['fields']['request_time']['custom_date_format'] = 'Y-m-d H:i:s';
+  /* Field: Feeds log: Log message */
+  $handler->display->display_options['fields']['message']['id'] = 'message';
+  $handler->display->display_options['fields']['message']['table'] = 'feeds_log';
+  $handler->display->display_options['fields']['message']['field'] = 'message';
+  $handler->display->display_options['fields']['message']['label'] = 'Message';
+  $handler->display->display_options['fields']['message']['hide_empty'] = 0;
+  $handler->display->display_options['fields']['message']['empty_zero'] = 0;
+  /* Field: Feeds log: Severity */
+  $handler->display->display_options['fields']['severity']['id'] = 'severity';
+  $handler->display->display_options['fields']['severity']['table'] = 'feeds_log';
+  $handler->display->display_options['fields']['severity']['field'] = 'severity';
+  $handler->display->display_options['fields']['severity']['hide_empty'] = 0;
+  $handler->display->display_options['fields']['severity']['empty_zero'] = 0;
+  /* Field: Feeds log: Importer name */
+  $handler->display->display_options['fields']['importer_name']['id'] = 'importer_name';
+  $handler->display->display_options['fields']['importer_name']['table'] = 'feeds_log';
+  $handler->display->display_options['fields']['importer_name']['field'] = 'importer_name';
+  $handler->display->display_options['fields']['importer_name']['label'] = 'Importer';
+  $handler->display->display_options['fields']['importer_name']['hide_empty'] = 0;
+  $handler->display->display_options['fields']['importer_name']['empty_zero'] = 0;
+  $handler->display->display_options['fields']['importer_name']['link'] = '2';
+  /* Field: Node: Title */
+  $handler->display->display_options['fields']['title']['id'] = 'title';
+  $handler->display->display_options['fields']['title']['table'] = 'node';
+  $handler->display->display_options['fields']['title']['field'] = 'title';
+  $handler->display->display_options['fields']['title']['relationship'] = 'feed_nid';
+  $handler->display->display_options['fields']['title']['label'] = 'Feed node';
+  $handler->display->display_options['fields']['title']['alter']['alter_text'] = 0;
+  $handler->display->display_options['fields']['title']['alter']['make_link'] = 0;
+  $handler->display->display_options['fields']['title']['alter']['absolute'] = 0;
+  $handler->display->display_options['fields']['title']['alter']['trim'] = 1;
+  $handler->display->display_options['fields']['title']['alter']['max_length'] = '40';
+  $handler->display->display_options['fields']['title']['alter']['word_boundary'] = 1;
+  $handler->display->display_options['fields']['title']['alter']['ellipsis'] = 1;
+  $handler->display->display_options['fields']['title']['alter']['strip_tags'] = 0;
+  $handler->display->display_options['fields']['title']['alter']['html'] = 0;
+  $handler->display->display_options['fields']['title']['hide_empty'] = 0;
+  $handler->display->display_options['fields']['title']['empty_zero'] = 0;
+  $handler->display->display_options['fields']['title']['link_to_node'] = 1;
+  $handler->display->display_options['defaults']['arguments'] = FALSE;
+  $handler->display->display_options['defaults']['filters'] = FALSE;
+  /* Filter: Feeds log: Severity */
+  $handler->display->display_options['filters']['severity']['id'] = 'severity';
+  $handler->display->display_options['filters']['severity']['table'] = 'feeds_log';
+  $handler->display->display_options['filters']['severity']['field'] = 'severity';
+  $handler->display->display_options['filters']['severity']['exposed'] = TRUE;
+  $handler->display->display_options['filters']['severity']['expose']['operator'] = 'severity_op';
+  $handler->display->display_options['filters']['severity']['expose']['label'] = 'Severity';
+  $handler->display->display_options['filters']['severity']['expose']['use_operator'] = FALSE;
+  $handler->display->display_options['filters']['severity']['expose']['identifier'] = 'severity';
+  $handler->display->display_options['filters']['severity']['expose']['reduce'] = 0;
+  $handler->display->display_options['path'] = 'admin/reports/feeds';
+  $handler->display->display_options['menu']['type'] = 'normal';
+  $handler->display->display_options['menu']['title'] = 'Feeds log';
+  $handler->display->display_options['menu']['description'] = 'Review log messages of imports and subscriptions to feeds.';
+  $handler->display->display_options['menu']['weight'] = '0';
+  $handler->display->display_options['menu']['name'] = 'management';
+
+  $views[$view->name] = $view;
+
+  return $views;
+}
Index: views/feeds_views_handler_argument_importer_id.inc
===================================================================
RCS file: views/feeds_views_handler_argument_importer_id.inc
diff -N views/feeds_views_handler_argument_importer_id.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ views/feeds_views_handler_argument_importer_id.inc	28 Nov 2010 03:18:47 -0000
@@ -0,0 +1,25 @@
+<?php
+// $Id: feeds_views_handler_argument_importer_id.inc,v 1.1.2.1 2010/10/26 03:05:58 alexb Exp $
+
+/**
+ * @file
+ * Argument handler for importer ids.
+ */
+class feeds_views_handler_argument_importer_id extends views_handler_argument_string {
+
+  /**
+   * Argument must be a valid importer id.
+   */
+  function validate_arg($arg) {
+    // By using % in URLs, arguments could be validated twice; this eases
+    // that pain.
+    if (isset($this->argument_validated)) {
+      return $this->argument_validated;
+    }
+    $this->argument_validated = FALSE;
+    if (in_array($arg, feeds_enabled_importers())) {
+      $this->argument_validated = TRUE;
+    }
+    return $this->argument_validated;
+  }
+}
Index: views/feeds_views_handler_field_importer_name.inc
===================================================================
RCS file: views/feeds_views_handler_field_importer_name.inc
diff -N views/feeds_views_handler_field_importer_name.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ views/feeds_views_handler_field_importer_name.inc	28 Nov 2010 03:18:47 -0000
@@ -0,0 +1,64 @@
+<?php
+// $Id: feeds_views_handler_field_importer_name.inc,v 1.1.2.1 2010/10/26 03:05:58 alexb Exp $
+
+/**
+ * @file
+ * Render an importer name.
+ */
+
+class feeds_views_handler_field_importer_name extends views_handler_field {
+
+  /**
+   * Overrides parent::option_definition().
+   */
+  function option_definition() {
+    $options = parent::option_definition();
+    $options['link'] = array('default' => 0);
+    return $options;
+  }
+
+  /**
+   * Overrides parent::options_form().
+   */
+  function options_form(&$form, &$form_state) {
+    parent::options_form($form, $form_state);
+    $options = array(
+      0 => t('Do not link'),
+      1 => t('Link to configuration form'),
+      2 => t('Link to standalone form'),
+    );
+    $form['link'] = array(
+      '#type' => 'radios',
+      '#title' => t('Link importer name'),
+      '#description' => t('If "Link to standalone form" is used, only importers that use a standalone form will be linked.'),
+      '#default_value' => isset($this->options['link']) ? $this->options['link'] : FALSE,
+      '#options' => $options,
+    );
+  }
+
+  /**
+   * Overrides parent::render().
+   */
+  function render($values) {
+    try {
+      $importer = feeds_importer($values->{$this->field_alias})->existing();
+      if ($this->options['link'] == 1) {
+        return l($importer->config['name'], 'admin/structure/feeds/' . $importer->id);
+      }
+      elseif ($this->options['link'] == 2 && empty($importer->config['content_type'])) {
+        return l($importer->config['name'], 'import/' . $importer->id);
+      }
+      return check_plain($importer->config['name']);
+    }
+    catch (Exception $e) {
+      return t('Missing importer');
+    }
+  }
+
+  /**
+   * Disallows advanced rendering.
+   */
+  function allow_advanced_render() {
+    return FALSE;
+  }
+}
Index: views/feeds_views_handler_field_log_message.inc
===================================================================
RCS file: views/feeds_views_handler_field_log_message.inc
diff -N views/feeds_views_handler_field_log_message.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ views/feeds_views_handler_field_log_message.inc	28 Nov 2010 03:18:47 -0000
@@ -0,0 +1,26 @@
+<?php
+// $Id: feeds_views_handler_field_log_message.inc,v 1.1.2.1 2010/10/26 03:05:58 alexb Exp $
+
+/**
+ * @file
+ * Views handler for displaying a log message.
+ */
+
+class feeds_views_handler_field_log_message extends views_handler_field {
+
+  /**
+   * Override parent::render().
+   */
+  function render($values) {
+    $message = $values->{$this->field_alias};
+    $variables = unserialize($values->{$this->aliases['variables']});
+    return t($message, $variables);
+  }
+
+  /**
+   * Disallow advanced rendering.
+   */
+  function allow_advanced_render() {
+    return FALSE;
+  }
+}
Index: views/feeds_views_handler_field_severity.inc
===================================================================
RCS file: views/feeds_views_handler_field_severity.inc
diff -N views/feeds_views_handler_field_severity.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ views/feeds_views_handler_field_severity.inc	28 Nov 2010 03:18:47 -0000
@@ -0,0 +1,26 @@
+<?php
+// $Id: feeds_views_handler_field_severity.inc,v 1.1.2.1 2010/10/26 03:05:58 alexb Exp $
+
+/**
+ * @file
+ * Views handler for displaying the logs severity field.
+ */
+
+class feeds_views_handler_field_severity extends views_handler_field {
+
+  /**
+   * Override parent::render().
+   */
+  function render($values) {
+    $value = $values->{$this->field_alias};
+    $levels = watchdog_severity_levels();
+    return $levels[$value];
+  }
+
+  /**
+   * Disallow advanced rendering.
+   */
+  function allow_advanced_render() {
+    return FALSE;
+  }
+}
Index: views/feeds_views_handler_filter_severity.inc
===================================================================
RCS file: views/feeds_views_handler_filter_severity.inc
diff -N views/feeds_views_handler_filter_severity.inc
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ views/feeds_views_handler_filter_severity.inc	28 Nov 2010 03:18:47 -0000
@@ -0,0 +1,14 @@
+<?php
+// $Id: feeds_views_handler_filter_severity.inc,v 1.1.2.1 2010/10/26 03:05:58 alexb Exp $
+
+/**
+ * @file
+ * Filter by severity.
+ */
+
+class feeds_views_handler_filter_severity extends views_handler_filter_in_operator {
+  function get_value_options() {
+    $this->value_title = t('Severity');
+    $this->value_options = watchdog_severity_levels();
+  }
+}
