Target.php 7.63 KB
Newer Older
w  
Qiang Xue committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<?php
/**
 * Target class file.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @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
16 17 18
 * 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
19 20
 *
 * Level filter and category filter are combinational, i.e., only messages
w  
Qiang Xue committed
21 22 23 24
 * 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
25 26 27 28 29 30 31 32 33 34 35
 *
 * @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
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
	 * @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
57
	 */
w  
Qiang Xue committed
58
	public $prefixSession = false;
w  
Qiang Xue committed
59
	/**
w  
Qiang Xue committed
60 61
	 * @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
62
	 */
w  
Qiang Xue committed
63
	public $prefixUser = false;
w  
Qiang Xue committed
64
	/**
w  
Qiang Xue committed
65 66
	 * @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
67
	 */
w  
Qiang Xue committed
68
	public $logUser = false;
w  
Qiang Xue committed
69
	/**
w  
Qiang Xue committed
70 71 72
	 * @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
73
	 */
w  
Qiang Xue committed
74
	public $logVars = array('_GET', '_POST', '_FILES', '_COOKIE', '_SESSION', '_SERVER');
w  
Qiang Xue committed
75
	/**
w  
Qiang Xue committed
76
	 * @var array the messages that are retrieved from the logger so far by this log target.
w  
Qiang Xue committed
77
	 */
w  
Qiang Xue committed
78
	public $messages = array();
w  
Qiang Xue committed
79 80

	/**
w  
Qiang Xue committed
81 82 83 84
	 * 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
85
	 */
w  
Qiang Xue committed
86
	abstract public function exportMessages($final);
w  
Qiang Xue committed
87 88 89 90 91 92 93 94 95 96 97

	/**
	 * 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
98 99 100 101 102 103 104
	 * 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
105
	 */
w  
Qiang Xue committed
106
	public function processMessages($messages, $export, $final)
w  
Qiang Xue committed
107
	{
w  
Qiang Xue committed
108 109 110 111 112 113 114
		$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
115 116 117
	}

	/**
w  
Qiang Xue committed
118
	 * Prepares the [[messages]] for exporting.
Qiang Xue committed
119
	 * This method will modify each message by prepending extra information
w  
Qiang Xue committed
120 121 122 123
	 * 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
124
	 */
w  
Qiang Xue committed
125
	protected function prepareExport($final)
w  
Qiang Xue committed
126
	{
w  
Qiang Xue committed
127 128 129 130
		$prefix = array();
		if ($this->prefixSession && ($id = session_id()) !== '') {
			$prefix[] = "[$id]";
		}
Qiang Xue committed
131
		if ($this->prefixUser && ($user = \Yii::$application->getComponent('user', false)) !== null) {
w  
Qiang Xue committed
132 133 134 135 136 137 138 139 140 141 142
			$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
143 144 145
		}
	}

w  
Qiang Xue committed
146 147 148 149 150 151
	/**
	 * 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
152
	{
w  
Qiang Xue committed
153
		$context = array();
Qiang Xue committed
154
		if ($this->logUser && ($user = \Yii::$application->getComponent('user', false)) !== null) {
w  
Qiang Xue committed
155 156 157 158 159 160 161
			$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
162
		}
w  
Qiang Xue committed
163 164

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

	/**
w  
Qiang Xue committed
168 169 170 171 172
	 * 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
173
	 */
w  
Qiang Xue committed
174
	protected function filterMessages($messages)
w  
Qiang Xue committed
175
	{
w  
Qiang Xue committed
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 205
		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
206
		}
w  
Qiang Xue committed
207
		return $messages;
w  
Qiang Xue committed
208 209 210
	}

	/**
w  
Qiang Xue committed
211 212 213 214
	 * 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
215
	 */
w  
Qiang Xue committed
216
	public function formatMessage($message)
w  
Qiang Xue committed
217
	{
w  
Qiang Xue committed
218
		return @date('Y/m/d H:i:s', $message[3]) . " [{$message[1]}] [{$message[2]}] {$message[0]}\n";
w  
Qiang Xue committed
219 220
	}
}