You are here

logs_http.module in Logs HTTP 7

Same filename and directory in other branches
  1. 8 logs_http.module

Logs HTTP module.

File

logs_http.module
View source
<?php

/**
 * @file
 * Logs HTTP module.
 */

/**
 * Implements hook_menu().
 */
function logs_http_menu() {
  $items = array();
  $items['admin/config/services/logs-http-client'] = array(
    'type' => MENU_NORMAL_ITEM,
    'title' => 'Logs HTTP Client',
    'description' => 'Administer Logs Client settings.',
    'access arguments' => array(
      'administer logs http client',
    ),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'logs_http_admin_settings',
    ),
    'file' => 'logs_http.admin.inc',
  );
  return $items;
}

/**
 * Implements hook_boot().
 *
 * Runs even for cached pages.
 */
function logs_http_boot() {
  drupal_register_shutdown_function('logs_http_shutdown');
  set_exception_handler('_logs_http_exception_handler');
}

/**
 * Provides custom PHP exception handling.
 *
 * Uncaught exceptions are those not enclosed in a try/catch block. They are
 * always fatal: the execution of the script will stop as soon as the exception
 * handler exits.
 *
 * @param $exception
 *   The exception object that was thrown.
 *
 * @see _drupal_exception_handler()
 */
function _logs_http_exception_handler($exception) {
  require_once DRUPAL_ROOT . '/includes/errors.inc';
  try {

    // Log the message to the watchdog and return an error page to the user.
    _drupal_log_error(_logs_http_decode_exception($exception), TRUE);
  } catch (Exception $exception2) {

    // Another uncaught exception was thrown while handling the first one.
    // If we are displaying errors, then do so with no possibility of a further uncaught exception being thrown.
    if (error_displayable()) {
      print '<h1>Additional uncaught exception thrown while handling exception.</h1>';
      print '<h2>Original</h2><p>' . _drupal_render_exception_safe($exception) . '</p>';
      print '<h2>Additional</h2><p>' . _drupal_render_exception_safe($exception2) . '</p><hr />';
    }
  }
}

/**
 * Decodes an exception and retrieves the correct caller.
 *
 * @param $exception
 *   The exception object that was thrown.
 *
 * @return array
 *   An error in the format expected by _drupal_log_error().
 *
 * @see _drupal_decode_exception()
 */
function _logs_http_decode_exception($exception) {
  $return = _drupal_decode_exception($exception);

  // We have to serialize and encode the array here to prevent a notice in
  // theme_dblog_message(). We will decode the string back in
  // logs_http_watchdog()
  $return['exception_trace'] = drupal_base64_encode(serialize($exception
    ->getTrace()));
  return $return;
}

/**
 * Runs on shutdown to clean up and display developer information.
 *
 * devel_boot() registers this function as a shutdown function.
 */
function logs_http_shutdown() {
  if (!($events = logs_http_get_registered_events())) {
    return;
  }
  $url = logs_http_get_http_url();

  // Send events to logs.
  foreach ($events as $event) {
    $options = array(
      'method' => 'POST',
      'data' => drupal_json_encode($event),
    );

    // Send data to Logs.
    $response = drupal_http_request($url, $options);
  }
}

/**
 * Register an event in a static cache.
 *
 * To prevent multiple registration of the same error, we check that identical
 * events are not captured twice, thus reducing the final HTTP requests needed.
 *
 * @param array $log_entry
 *   The entry log as passed from hook_watchdog().
 */
function logs_http_register_event(array $log_entry) {
  if (!logs_http_get_http_url()) {
    return;
  }
  $events =& drupal_static('logs_http_events', array());
  $event = array(
    'timestamp' => $log_entry['timestamp'],
    'type' => $log_entry['type'],
    'ip' => $log_entry['ip'],
    'request_uri' => $log_entry['request_uri'],
    'referer' => $log_entry['referer'],
    'uid' => $log_entry['uid'],
    'link' => strip_tags($log_entry['link']),
    'message' => empty($log_entry['variables']) ? $log_entry['message'] : strtr($log_entry['message'], $log_entry['variables']),
    'severity' => $log_entry['severity'],
  );
  if (!empty($log_entry['variables']['exception_trace'])) {

    // @todo: We avoid unserializing as it seems to causes Logs to fail
    // to index event as JSON.
    $event['exception_trace'] = base64_decode($log_entry['variables']['exception_trace']);
  }
  if ($uuid = variable_get('logs_http_uuid')) {
    $event['uuid'] = $uuid;
  }

  // Remove empty values, to prevent errors in the indexing of the JSON.
  $event = logs_http_array_remove_empty($event);

  // Prevent identical events.
  $event_clone = $event;
  unset($event_clone['timestamp']);
  $key = md5(serialize($event_clone));
  $events[$key] = $event;
}

/**
 * Get the registered events from the static cache.
 *
 * @return array
 *   Array of events.
 */
function logs_http_get_registered_events() {
  $events =& drupal_static('logs_http_events', array());
  return $events;
}

/**
 * Implements hook_permission().
 */
function logs_http_permission() {
  $permissions = array();
  $permissions['administer logs http client'] = array(
    'title' => t('Administer Logs HTTP client'),
  );
  return $permissions;
}

/**
 * Implements hook_watchdog().
 *
 * Register watchdog events.
 */
function logs_http_watchdog(array $log_entry) {
  if ($log_entry['severity'] > variable_get('logs_http_severity_level', WATCHDOG_ERROR)) {

    // Severity level is above the ones we want to log.
    return;
  }
  logs_http_register_event($log_entry);
}

/**
 * Return the endpoint URL to POST data to.
 *
 * @return string
 *   Return the URL if exists, or NULL if disabled.
 */
function logs_http_get_http_url() {
  if (!variable_get('logs_http_enabled', TRUE) || !variable_get('logs_http_url')) {

    // Don't register the event.
    return;
  }
  return variable_get('logs_http_url');
}

/**
 * Deep array filter.
 *
 * Remove empty values.
 *
 * @param $haystack
 *   The variable to filter.
 *
 * @return mixed
 */
function logs_http_array_remove_empty($haystack) {
  foreach ($haystack as $key => $value) {
    if (is_array($value)) {
      $haystack[$key] = logs_http_array_remove_empty($haystack[$key]);
    }
    if (empty($haystack[$key])) {
      unset($haystack[$key]);
    }
  }
  return $haystack;
}

Functions

Namesort descending Description
logs_http_array_remove_empty Deep array filter.
logs_http_boot Implements hook_boot().
logs_http_get_http_url Return the endpoint URL to POST data to.
logs_http_get_registered_events Get the registered events from the static cache.
logs_http_menu Implements hook_menu().
logs_http_permission Implements hook_permission().
logs_http_register_event Register an event in a static cache.
logs_http_shutdown Runs on shutdown to clean up and display developer information.
logs_http_watchdog Implements hook_watchdog().
_logs_http_decode_exception Decodes an exception and retrieves the correct caller.
_logs_http_exception_handler Provides custom PHP exception handling.