This repository was archived by the owner on Mar 3, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
By brian.reese: Created new Logger module.
- Loading branch information
1 parent
2767a71
commit d176436
Showing
9 changed files
with
402 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# Logger | ||
|
||
## Contents of This File | ||
|
||
- [Introduction](#introduction) | ||
- [Installation](#installation) | ||
- [Instrumentation](#instrumentation) | ||
|
||
|
||
## Introduction | ||
|
||
Current maintainer: [whitehouse](https://www.drupal.org/u/whitehouse) | ||
|
||
The Logger module provides event logging facilities that are decoupled from any | ||
particular storage backend. It is useful for module developers who want to | ||
instrument their code for monitoring and alerting without forcing their users | ||
to use a particular backend technology, like StatsD. The module doesn't provide | ||
any visible functionality out-of-the-box. You only need it if you're a module | ||
developer looking to instrument your code or if a module you're using depends on | ||
it. | ||
|
||
|
||
## Installation | ||
|
||
Logger itself is installed in the usual way. See [Installing contributed | ||
modules](https://www.drupal.org/documentation/install/modules-themes/modules-7). | ||
An implementation of `hook_logger_event()` is required to connect to a logging | ||
backend so as to actually do something with event data. See [logger.api.php] | ||
(logger.api.php). This implementation may be supplied in custom code or by a | ||
contributed module like [StatsD](https://www.drupal.org/project/statsd). | ||
|
||
|
||
## Instrumentation | ||
|
||
Instrumentation is the process of adding "probes" to your application code to | ||
fire events for Logger to log. If you're installing Logger as a dependency of | ||
another module, presumably that module is already instrumented. To instrument | ||
your own code, simply invoke `logger_event()`, much as you would [`watchdog()`] | ||
(https://api.drupal.org/api/drupal/includes!bootstrap.inc/function/watchdog/7). | ||
See [logger.module](logger.module). | ||
|
||
If you're instrumenting a contributed module, you must [declare a dependency on | ||
Logger in your .info file](https://www.drupal.org/node/542202#dependencies). | ||
Alternatively, you can create a "soft", or optional, dependency on Logger by | ||
using a wrapping function instead of calling `logger_event()` directly, like | ||
this: | ||
|
||
```php | ||
function example_logger_event($name, $type = 'count', $value = 1) { | ||
if (function_exists('logger_event')) { | ||
logger_event($name, $type, $value); | ||
} | ||
} | ||
``` | ||
|
||
Event names should be [Graphite](http://graphite.readthedocs.org/)-compatible, | ||
i.e., paths delimited by dots (`.`). See [Getting Your Data Into Graphite: Step 1] | ||
(http://graphite.readthedocs.org/en/latest/feeding-carbon.html#step-1-plan-a-naming-hierarchy) | ||
for some helpful advice. | ||
|
||
Note: Logger has a debug mode that logs events to watchdog, which can be helpful | ||
during development. It can be enabled at `admin/config/development/logging` or | ||
by setting the `logger_debug` variable directly, e.g.: | ||
|
||
```bash | ||
# Enable debugging. | ||
drush variable-set --exact logger_debug 1 | ||
# Disable debugging. | ||
drush variable-delete --exact logger_debug | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<?php | ||
|
||
/** | ||
* @file | ||
* Hooks provided by the Logger module. | ||
*/ | ||
|
||
/** | ||
* @addtogroup hooks | ||
* @{ | ||
*/ | ||
|
||
/** | ||
* Log a system event. | ||
* | ||
* This hook allows modules to log events to custom facilities, such as StatsD. | ||
* | ||
* @param string $name | ||
* The name of the event to log. | ||
* @param string $type | ||
* The type of metric to log--one of the following values corresponding to the | ||
* @link https://github.com/etsy/statsd/blob/master/docs/metric_types.md StatsD Metric Types @endlink | ||
* : | ||
* - count: The corresponding value is a number by which to increment (or | ||
* decrement, if negative) a simple counter. | ||
* - gauge: The corresponding value is a single datum, which remains constant | ||
* until explicitly changed. | ||
* - set: The corresponding value is a value to add to a set of unique values. | ||
* - time: The corresponding value is a duration in milliseconds. | ||
* @param int $value | ||
* The numeric value you wish to log. | ||
* | ||
* @see logger_event() | ||
*/ | ||
function hook_logger_event($name, $type, $value) { | ||
// Send the metric to StatsD. | ||
switch ($type) { | ||
case 'count': | ||
StatsD::updateStats($name, $value); | ||
break; | ||
|
||
case 'gauge': | ||
StatsD::gauge($name, $value); | ||
break; | ||
|
||
case 'time': | ||
StatsD::timing($name, $value); | ||
break; | ||
|
||
case 'set': | ||
// The StatsD module does not currently support the "set" type. | ||
break; | ||
} | ||
} | ||
|
||
/** | ||
* @} End of "addtogroup hooks". | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?php | ||
|
||
/** | ||
* @file | ||
* Form functions for the Logger module. | ||
*/ | ||
|
||
/** | ||
* Implements hook_form_alter(). | ||
*/ | ||
function logger_form_alter(&$form, &$form_state, $form_id) { | ||
// In order for hook_form_FORM_ID_alter() implementations to be detected in | ||
// this file, an implementation of hook_form_alter() is needed, even if empty. | ||
// @see https://api.drupal.org/comment/8714#comment-8714 | ||
} | ||
|
||
/** | ||
* Implements hook_form_FORM_ID_alter() for system_logging_settings(). | ||
*/ | ||
function logger_form_system_logging_settings_alter(&$form, &$form_state, $form_id) { | ||
$form['logger_debug'] = array( | ||
'#type' => 'checkbox', | ||
'#title' => t('Enable Logger debugging'), | ||
'#default_value' => variable_get('logger_debug', FALSE), | ||
'#description' => t('Log Logger events to Watchdog for debugging. <strong>Warning:</strong> This can add significant load to the database and should not be enabled in production under normal circumstances.'), | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
name = Logger | ||
description = Provides event logging facilities decoupled from storage backend. | ||
core = 7.x | ||
files[] = tests/logger.test | ||
package = Developer | ||
configure = admin/config/development/logging |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<?php | ||
|
||
/** | ||
* @file | ||
* Install, update and uninstall functions for the Logger module. | ||
*/ | ||
|
||
/** | ||
* Implements hook_uninstall(). | ||
*/ | ||
function logger_uninstall() { | ||
// Delete persistent variables. | ||
db_delete('variable') | ||
->condition('name', db_like('logger_') . '%', 'LIKE') | ||
->execute(); | ||
cache_clear_all('variables', 'cache_bootstrap'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<?php | ||
|
||
/** | ||
* @file | ||
* Provides event logging facilities decoupled from storage backend. | ||
*/ | ||
|
||
/** | ||
* Implements hook_hook_info_alter(). | ||
*/ | ||
function logger_hook_info_alter(&$hooks) { | ||
// Check HOOK.form.inc files for hook_form_alter() implementations. | ||
$hooks['form_alter']['group'] = 'form'; | ||
} | ||
|
||
/** | ||
* Logs a system event. | ||
* | ||
* Note: Backends like @link http://graphite.readthedocs.org/ Graphite @endlink | ||
* interpret dots (.) as path delimiters, like forward slashes (/) in a file | ||
* path. You need to account for this if part of your event name is dynamically | ||
* generated and may contain dots. For example: | ||
* | ||
* @code | ||
* $ip_address = str_replace('.', '_', $_SERVER['REMOTE_ADDR']); | ||
* logger_event(sprintf('server.remote_addr.%s', $ip_address); | ||
* @endcode | ||
* | ||
* @param string $name | ||
* The name of the event you want to log. | ||
* @param string $type | ||
* (optional) The type of metric to log--one of the following values | ||
* corresponding to the | ||
* @link https://github.com/etsy/statsd/blob/master/docs/metric_types.md StatsD Metric Types @endlink | ||
* : | ||
* - count: The corresponding value is a number by which to increment (or | ||
* decrement, if negative) a simple counter. | ||
* - gauge: The corresponding value is a single datum, which remains constant | ||
* until explicitly changed. | ||
* - set: The corresponding value is a value to add to a set of unique values. | ||
* - time: The corresponding value is a duration in milliseconds. | ||
* @param int $value | ||
* (optional) The numeric value you wish to log. Defaults to 1. | ||
* | ||
* @see hook_logger_event() | ||
*/ | ||
function logger_event($name, $type = 'count', $value = 1) { | ||
// Assert valid event type. | ||
$valid_types = array('count', 'gauge', 'set', 'time'); | ||
if (!in_array($type, $valid_types)) { | ||
throw new InvalidArgumentException(sprintf('Invalid event type: "%s".', $type)); | ||
} | ||
|
||
// Assert valid event value. | ||
if (!is_int($value)) { | ||
throw new InvalidArgumentException(sprintf('Invalid event value: "%s".', $value)); | ||
} | ||
|
||
// Conditionally log events to watchdog for debugging purposes. | ||
if (variable_get('logger_debug', FALSE)) { | ||
watchdog('logger', 'Logger Event: @name | @type | @value', array( | ||
'@name' => $name, | ||
'@type' => $type, | ||
'@value' => $value, | ||
), WATCHDOG_DEBUG); | ||
} | ||
|
||
module_invoke_all('logger_event', $name, $type, $value); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
<?php | ||
|
||
/** | ||
* @file | ||
* Tests for Logger module. | ||
*/ | ||
|
||
/** | ||
* Unit tests for Logger. | ||
*/ | ||
class LoggerUnitTestCase extends DrupalUnitTestCase { | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public static function getInfo() { | ||
return array( | ||
'name' => 'Logger unit tests', | ||
'description' => 'Test Logger classes and functions.', | ||
'group' => 'Logger', | ||
); | ||
} | ||
|
||
/** | ||
* Test valid arguments for logger_event(). | ||
*/ | ||
public function testValidLoggerEventFunction() { | ||
$test_cases = array(); | ||
$test_cases[] = array( | ||
'name' => 'test.valid_logger_event.name', | ||
'type' => 'count', | ||
'value' => 10, | ||
); | ||
|
||
foreach ($test_cases as $test_case) { | ||
try { | ||
logger_event($test_case['name'], $test_case['type'], $test_case['value']); | ||
$this->pass('Passed with valid "type" and "value" parameters'); | ||
} | ||
catch (InvalidArgumentException $e) { | ||
$this->fail($e->getMessage()); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* INVALID arguments for logger_event() are expected to throw exceptions. | ||
*/ | ||
public function testinvalidLoggerEventFunction() { | ||
$test_cases = array(); | ||
$test_cases[] = array( | ||
'name' => 'test.invalid_logger_event.name', | ||
'type' => '', | ||
'value' => '', | ||
'success_message' => t('Correctly threw exception for empty "value" parameter.'), | ||
'failure_message' => t('Incorrectly accepted an empty "value" parameter.'), | ||
); | ||
$test_cases[] = array( | ||
'name' => 'test.invalid_logger_event.name', | ||
'type' => 'invalidType', | ||
'value' => 10, | ||
'success_message' => t('Correctly threw exception for "type" parameter value not found in the $valid_types array.'), | ||
'failure_message' => t('Incorrectly accepted a "type" parameter value not found in the $valid_types array.'), | ||
); | ||
$test_cases[] = array( | ||
'name' => 'test.invalid_logger_event.name', | ||
'type' => 'count', | ||
'value' => 'invalidValue', | ||
'success_message' => t('Correctly threw exception for a non-integer "value" parameter value.'), | ||
'failure_message' => t('Incorrectly accepted a non-integer "value" parameter value.'), | ||
); | ||
|
||
foreach ($test_cases as $test_case) { | ||
try { | ||
logger_event($test_case['name'], $test_case['type'], $test_case['value']); | ||
$this->fail($test_case['failure_message']); | ||
} | ||
catch (InvalidArgumentException $e) { | ||
$this->pass($test_case['success_message'] . ' Exception messge: ' . | ||
$e->getMessage()); | ||
} | ||
} | ||
} | ||
|
||
} | ||
|
||
|
||
/** | ||
* Functional tests for Logger. | ||
*/ | ||
class LoggerWebTestCase extends DrupalWebTestCase { | ||
protected $privilegedUser; | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public static function getInfo() { | ||
return array( | ||
'name' => 'Logger functional tests', | ||
'description' => 'Test the functionality of Logger.', | ||
'group' => 'Logger', | ||
); | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function setUp() { | ||
parent::setUp('logger_test'); | ||
$permissions = array('access content'); | ||
$this->privilegedUser = $this->drupalCreateUser($permissions); | ||
$this->drupalLogin($this->privilegedUser); | ||
} | ||
|
||
/** | ||
* Test hook_logger_event(). | ||
* | ||
* @see logger_test_logger_event() | ||
*/ | ||
public function testHookLoggerEvent() { | ||
$expected_name = 'test.hook_logger_event.name'; | ||
$expected_type = 'count'; | ||
$expected_value = 100; | ||
logger_event($expected_name, $expected_type, $expected_value); | ||
$actual_name = variable_get('logger_test_name'); | ||
$actual_type = variable_get('logger_test_type'); | ||
$actual_value = variable_get('logger_test_value'); | ||
|
||
$this->assertEqual($actual_name, $expected_name, 'calling hook_logger_event with name ' . $expected_name); | ||
$this->assertEqual($actual_type, $expected_type, 'calling hook_logger_event with type ' . $expected_type); | ||
$this->assertEqual($actual_value, $expected_value, 'calling hook_logger_event with value ' . $expected_value); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
name = Logger tests | ||
description = Support module for logger testing. | ||
core = 7.x | ||
dependencies[] = logger | ||
package = Testing | ||
hidden = TRUE |
Oops, something went wrong.