Drupal watchdog, more productive

I have worked in numerous sites where watchdog has become useless by too many errors and warnings that flood this service. Some believe (and do) that they should disable altogether Database logging (dblog) module. My opinion is that this is totlly wrong. Watchdog can be really usefull, but in order for this to be the case extra care must be taken.

First of all, it is apparent that we must minimise all errors and warnings that happen too many times for all users (mostly anonymous), meaning that if by a single user visiting a single page we have for example 50 warnings, then we definitely check to see what happens. One problem could be module error, then we should try to update the module. One other reason could be bad server settings (which are needed for a spesific module), then we try to find a solution (Google, forums, etc).

After common issues have been fixed that food extremmely watchdog, then we try to fix other minor errors, that we were unable to identify before. This is a process of course that never stops. However, now it is more easy to do so. To make our life easier, I always use some extra modules. First of all, Better Watchdog UI (better_watchdog_ui) helps to create elaborate views and custom operations around watchdog entries. Furthermore, Views Bulk Operations (views_bulk_operations) helps remove watchdog entries in bulk mode. Till now, we base our work in ready made modules. Let's create something custom. I won't get into details around beginners questions, Drupal documentation is full of answers, but I will comment my new idea. In a module of our own, we create a new function:

function MY_MODULE_watchdog_remove_line($wid) {
  db_query("DELETE FROM {watchdog} WHERE wid = :wid LIMIT 1", array(':wid' => @intval($wid)));
  drupal_json_output('OK');
}
The above code is extremmely simple. It gets a unique watchdog entry (wid key) and deleted it from the watchdog table. At this point we don't care about security as this will be covered by the hook_menu, in which we add the following entry:
  $items['api/watchdog/%/remove'] = array(
    //  The same name of the function above
    'page callback' => 'MY_MODULE_watchdog_remove_line',
   
    // 0 ~> api
    // 1 ~> watchdog
    // 2 ~> wid number
    'page arguments' => array(2),
    
    // Only spesific people can access this api call
    'access arguments' => array('administer site configuration'),
   
    // No menu entry, just a plain callback    
    'type' => MENU_CALLBACK,
  );
 

The above code will give us an external api call, where spesific people are able to remove a watchdog without any confirmation. After that, we navigate to our watchdog view, newly created by the first module I mentioned (better_watchdog_ui) /admin/structure/views/view/better_watchdog_ui_view.  Here, we add two fields and one header field. The first one is wid rewritten as <a href="#" data-wid="[wid]" class="delete-wid-line">Remove</a>. The second one, which is based on Views PHP (views_php) in case is enabled, has value code return $row->severity; and output code <?php echo $value; ?>. This field is exluded from display. but is usefull to visualise rows differently by severity, and is optional, by adding class-severity-[php] in row class table settings tab. Finally, let's add Global: Text area in the header of our view with full html, with the following text:

<script>
jQuery(document).ready(function($){
  'use strict';
  $('a.delete-wid-line').click(function(e) {
    e.preventDefault();
    var $wid = $(this).attr('data-wid');
    var $tr = $(this).parent().parent();
    $tr.hide();
    $.get('/api/watchdog/'  + $wid + '/remove', function() {
      // Done
      console.log('Removed: ' + $wid);
    });
    return false;
  });
});
</script>
<style>
  .class-severity-7 { background: #fff !important; }
  .class-severity-6 { background: #EBFFD6 !important; }
  .class-severity-5 { background: #F5EBCC !important; }
  .class-severity-4 { background: #FFE0B2 !important; }
  .class-severity-3 { background: #FFFFCC !important; }
  .class-severity-2 { background: #F5E0CC !important; }
  .class-severity-1 { background: #FFD6CC !important; }
  .class-severity-0 { background: #FF4719 !important; }
</style>

First part is the javascript code executed when we press the "Remove" link in each watchdog entry row. This executes our api call to remove the watchdog entry from the databse, and then removes also the row of the displayed table to "visualise" the removal proccess. The second part is about the visual changes for each row per severity type. This is our exported view:

$view = new view();
$view->name = 'better_watchdog_ui_view';
$view->description = '';
$view->tag = 'default';
$view->base_table = 'watchdog';
$view->human_name = 'Watchdog';
$view->core = 7;
$view->api_version = '3.0';
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
 
/* Display: Master */
$handler = $view->new_display('default', 'Master', 'default');
$handler->display->display_options['title'] = 'Watchdog';
$handler->display->display_options['use_more_always'] = FALSE;
$handler->display->display_options['access']['type'] = 'perm';
$handler->display->display_options['access']['perm'] = 'access site reports';
$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['exposed_form']['options']['submit_button'] = 'Filter';
$handler->display->display_options['exposed_form']['options']['reset_button'] = TRUE;
$handler->display->display_options['exposed_form']['options']['reset_button_label'] = 'Επαναφορά';
$handler->display->display_options['pager']['type'] = 'full';
$handler->display->display_options['pager']['options']['items_per_page'] = '200';
$handler->display->display_options['pager']['options']['offset'] = '0';
$handler->display->display_options['pager']['options']['id'] = '0';
$handler->display->display_options['pager']['options']['quantity'] = '9';
$handler->display->display_options['pager']['options']['expose']['items_per_page'] = TRUE;
$handler->display->display_options['pager']['options']['expose']['items_per_page_options'] = '25, 50, 100, 200';
$handler->display->display_options['pager']['options']['tags']['first'] = '« πρώτη';
$handler->display->display_options['pager']['options']['tags']['previous'] = '‹ προηγούμενη';
$handler->display->display_options['pager']['options']['tags']['next'] = 'επόμενη ›';
$handler->display->display_options['pager']['options']['tags']['last'] = 'τελευταία »';
$handler->display->display_options['style_plugin'] = 'table';
$handler->display->display_options['style_options']['row_class'] = 'class-severity-[php]';
$handler->display->display_options['style_options']['columns'] = array(
  'views_bulk_operations' => 'views_bulk_operations',
  'severity' => 'severity',
  'type' => 'type',
  'timestamp' => 'timestamp',
  'wid' => 'wid',
  'message' => 'message',
  'uid' => 'uid',
  'php' => 'php',
);
$handler->display->display_options['style_options']['default'] = 'timestamp';
$handler->display->display_options['style_options']['info'] = array(
  'views_bulk_operations' => array(
    'align' => 'views-align-center',
    'separator' => '',
    'empty_column' => 0,
  ),
  'severity' => array(
    'sortable' => 1,
    'default_sort_order' => 'asc',
    'align' => 'views-align-center',
    'separator' => '',
    'empty_column' => 0,
  ),
  'type' => array(
    'sortable' => 1,
    'default_sort_order' => 'asc',
    'align' => 'views-align-center',
    'separator' => '<br/>',
    'empty_column' => 0,
  ),
  'timestamp' => array(
    'sortable' => 1,
    'default_sort_order' => 'desc',
    'align' => 'views-align-center',
    'separator' => '',
    'empty_column' => 0,
  ),
  'wid' => array(
    'sortable' => 0,
    'default_sort_order' => 'asc',
    'align' => 'views-align-center',
    'separator' => '',
    'empty_column' => 0,
  ),
  'message' => array(
    'sortable' => 0,
    'default_sort_order' => 'asc',
    'align' => '',
    'separator' => '',
    'empty_column' => 0,
  ),
  'uid' => array(
    'sortable' => 1,
    'default_sort_order' => 'asc',
    'align' => 'views-align-center',
    'separator' => '',
    'empty_column' => 0,
  ),
  'php' => array(
    'align' => '',
    'separator' => '',
    'empty_column' => 0,
  ),
);
/* Κεφαλίδα: Global: Text area */
$handler->display->display_options['header']['area']['id'] = 'area';
$handler->display->display_options['header']['area']['table'] = 'views';
$handler->display->display_options['header']['area']['field'] = 'area';
$handler->display->display_options['header']['area']['content'] = '<script>
jQuery(document).ready(function($){
  \'use strict\';
  $(\'a.delete-wid-line\').click(function(e) {
    e.preventDefault();
    var $wid = $(this).attr(\'data-wid\');
    var $tr = $(this).parent().parent();
    $tr.hide();
    $.get(\'/api/watchdog/\'  + $wid + \'/remove\', function() {
      // Done
      console.log(\'Removed: \' + $wid);
    });
    return false;
  });
});
</script>
<style>
  .class-severity-7 { background: #fff !important; }
  .class-severity-6 { background: #EBFFD6 !important; }
  .class-severity-5 { background: #F5EBCC !important; }
  .class-severity-4 { background: #FFE0B2 !important; }
  .class-severity-3 { background: #FFFFCC !important; }
  .class-severity-2 { background: #F5E0CC !important; }
  .class-severity-1 { background: #FFD6CC !important; }
  .class-severity-0 { background: #FF4719 !important; }
</style>';
$handler->display->display_options['header']['area']['format'] = 'full_html_without_editor';
/* No results behavior: 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'] = TRUE;
$handler->display->display_options['empty']['area']['content'] = 'No log entries or no log messages meet the search criteria.';
$handler->display->display_options['empty']['area']['format'] = 'filtered_html';
/* Πεδίο: Bulk operations: Watchdog */
$handler->display->display_options['fields']['views_bulk_operations']['id'] = 'views_bulk_operations';
$handler->display->display_options['fields']['views_bulk_operations']['table'] = 'watchdog';
$handler->display->display_options['fields']['views_bulk_operations']['field'] = 'views_bulk_operations';
$handler->display->display_options['fields']['views_bulk_operations']['label'] = 'Clear selected log messages';
$handler->display->display_options['fields']['views_bulk_operations']['vbo_settings']['display_type'] = '1';
$handler->display->display_options['fields']['views_bulk_operations']['vbo_settings']['enable_select_all_pages'] = 1;
$handler->display->display_options['fields']['views_bulk_operations']['vbo_settings']['force_single'] = 0;
$handler->display->display_options['fields']['views_bulk_operations']['vbo_settings']['entity_load_capacity'] = '50';
$handler->display->display_options['fields']['views_bulk_operations']['vbo_operations'] = array(
  'action::views_bulk_operations_delete_item' => array(
    'selected' => 1,
    'postpone_processing' => 0,
    'skip_confirmation' => 0,
    'override_label' => 1,
    'label' => 'Clear selected log messages',
  ),
  'action::views_bulk_operations_script_action' => array(
    'selected' => 0,
    'postpone_processing' => 0,
    'skip_confirmation' => 0,
    'override_label' => 0,
    'label' => '',
  ),
  'action::views_bulk_operations_modify_action' => array(
    'selected' => 0,
    'postpone_processing' => 0,
    'skip_confirmation' => 0,
    'override_label' => 0,
    'label' => '',
    'settings' => array(
      'show_all_tokens' => 1,
      'display_values' => array(
        '_all_' => '_all_',
      ),
    ),
  ),
  'action::views_bulk_operations_argument_selector_action' => array(
    'selected' => 0,
    'skip_confirmation' => 0,
    'override_label' => 0,
    'label' => '',
    'settings' => array(
      'url' => '',
    ),
  ),
  'action::system_send_email_action' => array(
    'selected' => 0,
    'postpone_processing' => 0,
    'skip_confirmation' => 0,
    'override_label' => 0,
    'label' => '',
  ),
);
/* Πεδίο: Watchdog: Σοβαρότητα */
$handler->display->display_options['fields']['severity']['id'] = 'severity';
$handler->display->display_options['fields']['severity']['table'] = 'watchdog';
$handler->display->display_options['fields']['severity']['field'] = 'severity';
/* Πεδίο: Watchdog: Τύπος */
$handler->display->display_options['fields']['type']['id'] = 'type';
$handler->display->display_options['fields']['type']['table'] = 'watchdog';
$handler->display->display_options['fields']['type']['field'] = 'type';
/* Πεδίο: Watchdog: Ημερομηνία */
$handler->display->display_options['fields']['timestamp']['id'] = 'timestamp';
$handler->display->display_options['fields']['timestamp']['table'] = 'watchdog';
$handler->display->display_options['fields']['timestamp']['field'] = 'timestamp';
$handler->display->display_options['fields']['timestamp']['label'] = 'Date';
$handler->display->display_options['fields']['timestamp']['date_format'] = 'short';
/* Πεδίο: Watchdog: Wid */
$handler->display->display_options['fields']['wid']['id'] = 'wid';
$handler->display->display_options['fields']['wid']['table'] = 'watchdog';
$handler->display->display_options['fields']['wid']['field'] = 'wid';
$handler->display->display_options['fields']['wid']['label'] = '';
$handler->display->display_options['fields']['wid']['alter']['alter_text'] = TRUE;
$handler->display->display_options['fields']['wid']['alter']['text'] = '<a href="#" data-wid="[wid]" class="delete-wid-line">Remove</a>';
$handler->display->display_options['fields']['wid']['element_label_colon'] = FALSE;
$handler->display->display_options['fields']['wid']['separator'] = '';
/* Πεδίο: Watchdog: Μήνυμα */
$handler->display->display_options['fields']['message']['id'] = 'message';
$handler->display->display_options['fields']['message']['table'] = 'watchdog';
$handler->display->display_options['fields']['message']['field'] = 'message';
$handler->display->display_options['fields']['message']['alter']['max_length'] = '100';
$handler->display->display_options['fields']['message']['alter']['strip_tags'] = TRUE;
$handler->display->display_options['fields']['message']['alter']['trim'] = TRUE;
/* Πεδίο: Watchdog: Χρήστης */
$handler->display->display_options['fields']['uid']['id'] = 'uid';
$handler->display->display_options['fields']['uid']['table'] = 'watchdog';
$handler->display->display_options['fields']['uid']['field'] = 'uid';
/* Πεδίο: Severity as int */
$handler->display->display_options['fields']['php']['id'] = 'php';
$handler->display->display_options['fields']['php']['table'] = 'views';
$handler->display->display_options['fields']['php']['field'] = 'php';
$handler->display->display_options['fields']['php']['ui_name'] = 'Severity as int';
$handler->display->display_options['fields']['php']['label'] = '';
$handler->display->display_options['fields']['php']['exclude'] = TRUE;
$handler->display->display_options['fields']['php']['element_label_colon'] = FALSE;
$handler->display->display_options['fields']['php']['use_php_setup'] = 0;
$handler->display->display_options['fields']['php']['php_value'] = 'return $row->severity;';
$handler->display->display_options['fields']['php']['php_output'] = '<?php echo $value; ?>';
$handler->display->display_options['fields']['php']['use_php_click_sortable'] = '0';
$handler->display->display_options['fields']['php']['php_click_sortable'] = '';
/* Filter criterion: Watchdog: Τύπος */
$handler->display->display_options['filters']['type']['id'] = 'type';
$handler->display->display_options['filters']['type']['table'] = 'watchdog';
$handler->display->display_options['filters']['type']['field'] = 'type';
$handler->display->display_options['filters']['type']['group'] = 1;
$handler->display->display_options['filters']['type']['exposed'] = TRUE;
$handler->display->display_options['filters']['type']['expose']['operator_id'] = 'type_op';
$handler->display->display_options['filters']['type']['expose']['label'] = 'Type';
$handler->display->display_options['filters']['type']['expose']['use_operator'] = TRUE;
$handler->display->display_options['filters']['type']['expose']['operator'] = 'type_op';
$handler->display->display_options['filters']['type']['expose']['identifier'] = 'type';
$handler->display->display_options['filters']['type']['expose']['multiple'] = TRUE;
$handler->display->display_options['filters']['type']['expose']['remember_roles'] = array(
  2 => '2',
  1 => 0,
  3 => 0,
);
/* Filter criterion: Watchdog: Σοβαρότητα */
$handler->display->display_options['filters']['severity']['id'] = 'severity';
$handler->display->display_options['filters']['severity']['table'] = 'watchdog';
$handler->display->display_options['filters']['severity']['field'] = 'severity';
$handler->display->display_options['filters']['severity']['group'] = 1;
$handler->display->display_options['filters']['severity']['exposed'] = TRUE;
$handler->display->display_options['filters']['severity']['expose']['operator_id'] = 'severity_op';
$handler->display->display_options['filters']['severity']['expose']['label'] = 'Severity';
$handler->display->display_options['filters']['severity']['expose']['use_operator'] = TRUE;
$handler->display->display_options['filters']['severity']['expose']['operator'] = 'severity_op';
$handler->display->display_options['filters']['severity']['expose']['identifier'] = 'severity';
$handler->display->display_options['filters']['severity']['expose']['multiple'] = TRUE;
$handler->display->display_options['filters']['severity']['expose']['remember_roles'] = array(
  2 => '2',
  1 => 0,
  3 => 0,
);
/* Filter criterion: Watchdog: Ημερομηνία */
$handler->display->display_options['filters']['timestamp']['id'] = 'timestamp';
$handler->display->display_options['filters']['timestamp']['table'] = 'watchdog';
$handler->display->display_options['filters']['timestamp']['field'] = 'timestamp';
$handler->display->display_options['filters']['timestamp']['operator'] = 'between';
$handler->display->display_options['filters']['timestamp']['group'] = 1;
$handler->display->display_options['filters']['timestamp']['exposed'] = TRUE;
$handler->display->display_options['filters']['timestamp']['expose']['operator_id'] = 'timestamp_op';
$handler->display->display_options['filters']['timestamp']['expose']['label'] = 'Date';
$handler->display->display_options['filters']['timestamp']['expose']['description'] = 'Preferred format: CCYY-MM-DD HH:MM:SS';
$handler->display->display_options['filters']['timestamp']['expose']['use_operator'] = TRUE;
$handler->display->display_options['filters']['timestamp']['expose']['operator'] = 'timestamp_op';
$handler->display->display_options['filters']['timestamp']['expose']['identifier'] = 'timestamp';
$handler->display->display_options['filters']['timestamp']['expose']['remember_roles'] = array(
  2 => '2',
  1 => 0,
  3 => 0,
);
/* Filter criterion: Watchdog: Χρήστης */
$handler->display->display_options['filters']['uid']['id'] = 'uid';
$handler->display->display_options['filters']['uid']['table'] = 'watchdog';
$handler->display->display_options['filters']['uid']['field'] = 'uid';
$handler->display->display_options['filters']['uid']['value'] = '';
$handler->display->display_options['filters']['uid']['exposed'] = TRUE;
$handler->display->display_options['filters']['uid']['expose']['operator_id'] = 'uid_op';
$handler->display->display_options['filters']['uid']['expose']['label'] = 'User';
$handler->display->display_options['filters']['uid']['expose']['use_operator'] = TRUE;
$handler->display->display_options['filters']['uid']['expose']['operator'] = 'uid_op';
$handler->display->display_options['filters']['uid']['expose']['identifier'] = 'uid';
$handler->display->display_options['filters']['uid']['expose']['remember_roles'] = array(
  2 => '2',
  1 => 0,
  3 => 0,
);
 
/* Display: Page */
$handler = $view->new_display('page', 'Page', 'page');
$handler->display->display_options['defaults']['hide_admin_links'] = FALSE;
$handler->display->display_options['path'] = 'admin/reports/dblog';
$translatables['better_watchdog_ui_view'] = array(
  t('Master'),
  t('Watchdog'),
  t('more'),
  t('Filter'),
  t('Επαναφορά'),
  t('Sort by'),
  t('Asc'),
  t('Desc'),
  t('Items per page'),
  t('- All -'),
  t('Offset'),
  t('« πρώτη'),
  t('‹ προηγούμενη'),
  t('επόμενη ›'),
  t('τελευταία »'),
  t('<script>
jQuery(document).ready(function($){
  \'use strict\';
  $(\'a.delete-wid-line\').click(function(e) {
    e.preventDefault();
    var $wid = $(this).attr(\'data-wid\');
    var $tr = $(this).parent().parent();
    $tr.hide();
    $.get(\'/api/watchdog/\'  + $wid + \'/remove\', function() {
      // Done
      console.log(\'Removed: \' + $wid);
    });
    return false;
  });
});
</script>
<style>
  .class-severity-7 { background: #fff !important; }
  .class-severity-6 { background: #EBFFD6 !important; }
  .class-severity-5 { background: #F5EBCC !important; }
  .class-severity-4 { background: #FFE0B2 !important; }
  .class-severity-3 { background: #FFFFCC !important; }
  .class-severity-2 { background: #F5E0CC !important; }
  .class-severity-1 { background: #FFD6CC !important; }
  .class-severity-0 { background: #FF4719 !important; }
</style>'),
  t('No log entries or no log messages meet the search criteria.'),
  t('Clear selected log messages'),
  t('- Choose an operation -'),
  t('Σοβαρότητα'),
  t('Τύπος'),
  t('Date'),
  t('<a href="#" data-wid="[wid]" class="delete-wid-line">Remove</a>'),
  t('.'),
  t('Μήνυμα'),
  t('Χρήστης'),
  t('Type'),
  t('Severity'),
  t('Preferred format: CCYY-MM-DD HH:MM:SS'),
  t('User'),
  t('Page'),
);
 

Linked In Profile