Target.php 7.59 KB
Newer Older
w  
Qiang Xue committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14
<?php
/**
 * Target class file.
 *
 * @link http://www.yiiframework.com/
 * @copyright Copyright &copy; 2008-2012 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 */

namespace yii\logging;

/**
 * Target is the base class for all log target classes.
 *
w  
Qiang Xue committed
15 16 17
 * A log target object will filter the messages logged by [[Logger]] according
 * to its [[levels]] and [[categories]] properties. It may also export the filtered
 * messages to specific destination defined by the target, such as emails, files.
w  
Qiang Xue committed
18 19
 *
 * Level filter and category filter are combinational, i.e., only messages
w  
Qiang Xue committed
20 21 22 23
 * satisfying both filter conditions will they be returned.  Additionally, you
 * may specify [[excludeCategories]]. If a message's category falls within the excluded
 * categories, it will be filtered out, even if it passes the [[levels]] and
 * [[categories]] filters.
w  
Qiang Xue committed
24 25 26 27 28 29 30 31 32 33 34
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @since 2.0
 */
abstract class Target extends \yii\base\Component implements \yii\base\Initable
{
	/**
	 * @var boolean whether to enable this log target. Defaults to true.
	 */
	public $enabled = true;
	/**
w  
Qiang Xue committed
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
	 * @var array list of message levels that this target is interested in. Defaults to empty, meaning all levels.
	 */
	public $levels = array();
	/**
	 * @var array list of message categories that this target is interested in. Defaults to empty, meaning all categories.
	 * You can use an asterisk at the end of a category so that the category may be used to
	 * match those categories sharing the same common prefix. For example, 'yii\db\*' will match
	 * categories starting with 'yii\db\', such as 'yii\db\dao\Connection'.
	 */
	public $categories = array();
	/**
	 * @var array list of message categories that this target is NOT interested in. Defaults to empty, meaning no uninteresting messages.
	 * If this property is not empty, then any category listed here will be excluded from [[categories]].
	 * You can use an asterisk at the end of a category so that the category can be used to
	 * match those categories sharing the same common prefix. For example, 'yii\db\*' will match
	 * categories starting with 'yii\db\', such as 'yii\db\dao\Connection'.
	 * @see categories
	 */
	public $excludeCategories = array();
	/**
	 * @var boolean whether to prefix each log message with the current session ID. Defaults to false.
w  
Qiang Xue committed
56
	 */
w  
Qiang Xue committed
57
	public $prefixSession = false;
w  
Qiang Xue committed
58
	/**
w  
Qiang Xue committed
59 60
	 * @var boolean whether to prefix each log message with the current user name and ID. Defaults to false.
	 * @see \yii\web\User
w  
Qiang Xue committed
61
	 */
w  
Qiang Xue committed
62
	public $prefixUser = false;
w  
Qiang Xue committed
63
	/**
w  
Qiang Xue committed
64 65
	 * @var boolean whether to log a message containing the current user name and ID. Defaults to true.
	 * @see \yii\web\User
w  
Qiang Xue committed
66
	 */
w  
Qiang Xue committed
67
	public $logUser = false;
w  
Qiang Xue committed
68
	/**
w  
Qiang Xue committed
69 70 71
	 * @var array list of the PHP predefined variables that should be logged in a message.
	 * Note that a variable must be accessible via `$GLOBALS`. Otherwise it won't be logged.
	 * Defaults to `array('_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER')`.
w  
Qiang Xue committed
72
	 */
w  
Qiang Xue committed
73
	public $logVars = array('_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER');
w  
Qiang Xue committed
74
	/**
w  
Qiang Xue committed
75
	 * @var array the messages that are retrieved from the logger so far by this log target.
w  
Qiang Xue committed
76
	 */
w  
Qiang Xue committed
77
	public $messages = array();
w  
Qiang Xue committed
78 79

	/**
w  
Qiang Xue committed
80 81 82 83
	 * Exports log messages to a specific destination.
	 * Child classes must implement this method. Note that you may need
	 * to clean up [[messages]] in this method to avoid re-exporting messages.
	 * @param boolean $final whether this method is called at the end of the current application
w  
Qiang Xue committed
84
	 */
w  
Qiang Xue committed
85
	abstract public function exportMessages($final);
w  
Qiang Xue committed
86 87 88 89 90 91 92 93 94 95 96

	/**
	 * Initializes this component.
	 * This method is invoked after the component is created and its property values are
	 * initialized.
	 */
	public function init()
	{
	}

	/**
w  
Qiang Xue committed
97 98 99 100 101 102 103
	 * Processes the given log messages.
	 * This method will filter the given messages with [[levels]] and [[categories]].
	 * And if requested, it will also export the filtering result to specific medium (e.g. email).
	 * @param array $messages log messages to be processed. See [[Logger::messages]] for the structure
	 * of each message.
	 * @param boolean $export whether to export the processing result
	 * @param boolean $final whether this method is called at the end of the current application
w  
Qiang Xue committed
104
	 */
w  
Qiang Xue committed
105
	public function processMessages($messages, $export, $final)
w  
Qiang Xue committed
106
	{
w  
Qiang Xue committed
107 108 109 110 111 112 113
		$messages = $this->filterMessages($messages);
		$this->messages = array_merge($this->messages, $messages);

		if ($export && !empty($this->messages)) {
			$this->prepareExport($final);
			$this->exportMessages($final);
		}
w  
Qiang Xue committed
114 115 116
	}

	/**
w  
Qiang Xue committed
117
	 * Prepares the [[messages]] for exporting.
Qiang Xue committed
118
	 * This method will modify each message by prepending extra information
w  
Qiang Xue committed
119 120 121 122
	 * if [[prefixSession]] and/or [[prefixUser]] are set true.
	 * It will also add an additional message showing context information if
	 * [[logUser]] and/or [[logVars]] are set.
	 * @param boolean $final whether this method is called at the end of the current application
w  
Qiang Xue committed
123
	 */
w  
Qiang Xue committed
124
	protected function prepareExport($final)
w  
Qiang Xue committed
125
	{
w  
Qiang Xue committed
126 127 128 129
		$prefix = array();
		if ($this->prefixSession && ($id = session_id()) !== '') {
			$prefix[] = "[$id]";
		}
Qiang Xue committed
130
		if ($this->prefixUser && ($user = \Yii::$application->getComponent('user', false)) !== null) {
w  
Qiang Xue committed
131 132 133 134 135 136 137 138 139 140 141
			$prefix[] = '[' . $user->getName() . ']';
			$prefix[] = '[' . $user->getId() . ']';
		}
		if ($prefix !== array()) {
			$prefix = implode(' ', $prefix);
			foreach ($this->messages as $i => $message) {
				$this->messages[$i][0] = $prefix . ' ' . $this->messages[$i][0];
			}
		}
		if ($final && ($context = $this->getContextMessage()) !== '') {
			$this->messages[] = array($context, Logger::LEVEL_INFO, 'application', YII_BEGIN_TIME);
w  
Qiang Xue committed
142 143 144
		}
	}

w  
Qiang Xue committed
145 146 147 148 149 150
	/**
	 * Generates the context information to be logged.
	 * The default implementation will dump user information, system variables, etc.
	 * @return string the context information. If an empty string, it means no context information.
	 */
	protected function getContextMessage()
w  
Qiang Xue committed
151
	{
w  
Qiang Xue committed
152
		$context = array();
Qiang Xue committed
153
		if ($this->logUser && ($user = \Yii::$application->getComponent('user', false)) !== null) {
w  
Qiang Xue committed
154 155 156 157 158 159 160
			$context[] = 'User: ' . $user->getName() . ' (ID: ' . $user->getId() . ')';
		}

		foreach ($this->logVars as $name) {
			if (!empty($GLOBALS[$name])) {
				$context[] = "\${$name} = " . var_export($GLOBALS[$name], true);
			}
w  
Qiang Xue committed
161
		}
w  
Qiang Xue committed
162 163

		return implode("\n\n", $context);
w  
Qiang Xue committed
164 165 166
	}

	/**
w  
Qiang Xue committed
167 168 169 170 171
	 * Filters the given messages according to their categories and levels.
	 * @param array $messages messages to be filtered
	 * @return array the filtered messages.
	 * @see filterByCategory
	 * @see filterByLevel
w  
Qiang Xue committed
172
	 */
w  
Qiang Xue committed
173
	protected function filterMessages($messages)
w  
Qiang Xue committed
174
	{
w  
Qiang Xue committed
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
		foreach ($messages as $i => $message) {
			if (!empty($this->levels) && !in_array($message[1], $this->levels)) {
				unset($messages[$i]);
				continue;
			}

			$matched = empty($this->categories);
			foreach ($this->categories as $category) {
				$prefix = rtrim($category, '*');
				if (strpos($message[2], $prefix) === 0 && ($message[2] === $category || $prefix !== $category)) {
					$matched = true;
					break;
				}
			}

			if ($matched) {
				foreach ($this->excludeCategories as $category) {
					$prefix = rtrim($category, '*');
					foreach ($messages as $i => $message) {
						if (strpos($message[2], $prefix) === 0 && ($message[2] === $category || $prefix !== $category)) {
							$matched = false;
							break;
						}
					}
				}
			}

			if (!$matched) {
				unset($messages[$i]);
			}
w  
Qiang Xue committed
205
		}
w  
Qiang Xue committed
206
		return $messages;
w  
Qiang Xue committed
207 208 209
	}

	/**
w  
Qiang Xue committed
210 211 212 213
	 * Formats a log message.
	 * The message structure follows that in [[Logger::messages]].
	 * @param array $message the log message to be formatted.
	 * @return string the formatted message
w  
Qiang Xue committed
214
	 */
w  
Qiang Xue committed
215
	public function formatMessage($message)
w  
Qiang Xue committed
216
	{
w  
Qiang Xue committed
217
		return @date('Y/m/d H:i:s', $message[3]) . " [{$message[1]}] [{$message[2]}] {$message[0]}\n";
w  
Qiang Xue committed
218 219
	}
}