123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. <?php
  2. /**
  3. * @link http://www.yiiframework.com/
  4. * @copyright Copyright (c) 2008 Yii Software LLC
  5. * @license http://www.yiiframework.com/license/
  6. */
  7. namespace yii\log;
  8. use Yii;
  9. use yii\base\Component;
  10. use yii\base\ErrorHandler;
  11. /**
  12. * Dispatcher manages a set of [[Target|log targets]].
  13. *
  14. * Dispatcher implements the [[dispatch()]]-method that forwards the log messages from a [[Logger]] to
  15. * the registered log [[targets]].
  16. *
  17. * An instance of Dispatcher is registered as a core application component and can be accessed using `Yii::$app->log`.
  18. *
  19. * You may configure the targets in application configuration, like the following:
  20. *
  21. * ```php
  22. * [
  23. * 'components' => [
  24. * 'log' => [
  25. * 'targets' => [
  26. * 'file' => [
  27. * 'class' => 'yii\log\FileTarget',
  28. * 'levels' => ['trace', 'info'],
  29. * 'categories' => ['yii\*'],
  30. * ],
  31. * 'email' => [
  32. * 'class' => 'yii\log\EmailTarget',
  33. * 'levels' => ['error', 'warning'],
  34. * 'message' => [
  35. * 'to' => 'admin@example.com',
  36. * ],
  37. * ],
  38. * ],
  39. * ],
  40. * ],
  41. * ]
  42. * ```
  43. *
  44. * Each log target can have a name and can be referenced via the [[targets]] property as follows:
  45. *
  46. * ```php
  47. * Yii::$app->log->targets['file']->enabled = false;
  48. * ```
  49. *
  50. * @property integer $flushInterval How many messages should be logged before they are sent to targets. This
  51. * method returns the value of [[Logger::flushInterval]].
  52. * @property Logger $logger The logger. If not set, [[\Yii::getLogger()]] will be used. Note that the type of
  53. * this property differs in getter and setter. See [[getLogger()]] and [[setLogger()]] for details.
  54. * @property integer $traceLevel How many application call stacks should be logged together with each message.
  55. * This method returns the value of [[Logger::traceLevel]]. Defaults to 0.
  56. *
  57. * @author Qiang Xue <qiang.xue@gmail.com>
  58. * @since 2.0
  59. */
  60. class Dispatcher extends Component
  61. {
  62. /**
  63. * @var array|Target[] the log targets. Each array element represents a single [[Target|log target]] instance
  64. * or the configuration for creating the log target instance.
  65. */
  66. public $targets = [];
  67. /**
  68. * @var Logger the logger.
  69. */
  70. private $_logger;
  71. /**
  72. * @inheritdoc
  73. */
  74. public function __construct($config = [])
  75. {
  76. // ensure logger gets set before any other config option
  77. if (isset($config['logger'])) {
  78. $this->setLogger($config['logger']);
  79. unset($config['logger']);
  80. }
  81. // connect logger and dispatcher
  82. $this->getLogger();
  83. parent::__construct($config);
  84. }
  85. /**
  86. * @inheritdoc
  87. */
  88. public function init()
  89. {
  90. parent::init();
  91. foreach ($this->targets as $name => $target) {
  92. if (!$target instanceof Target) {
  93. $this->targets[$name] = Yii::createObject($target);
  94. }
  95. }
  96. }
  97. /**
  98. * Gets the connected logger.
  99. * If not set, [[\Yii::getLogger()]] will be used.
  100. * @property Logger the logger. If not set, [[\Yii::getLogger()]] will be used.
  101. * @return Logger the logger.
  102. */
  103. public function getLogger()
  104. {
  105. if ($this->_logger === null) {
  106. $this->setLogger(Yii::getLogger());
  107. }
  108. return $this->_logger;
  109. }
  110. /**
  111. * Sets the connected logger.
  112. * @param Logger|string|array $value the logger to be used. This can either be a logger instance
  113. * or a configuration that will be used to create one using [[Yii::createObject()]].
  114. */
  115. public function setLogger($value)
  116. {
  117. if (is_string($value) || is_array($value)) {
  118. $value = Yii::createObject($value);
  119. }
  120. $this->_logger = $value;
  121. $this->_logger->dispatcher = $this;
  122. }
  123. /**
  124. * @return integer how many application call stacks should be logged together with each message.
  125. * This method returns the value of [[Logger::traceLevel]]. Defaults to 0.
  126. */
  127. public function getTraceLevel()
  128. {
  129. return $this->getLogger()->traceLevel;
  130. }
  131. /**
  132. * @param integer $value how many application call stacks should be logged together with each message.
  133. * This method will set the value of [[Logger::traceLevel]]. If the value is greater than 0,
  134. * at most that number of call stacks will be logged. Note that only application call stacks are counted.
  135. * Defaults to 0.
  136. */
  137. public function setTraceLevel($value)
  138. {
  139. $this->getLogger()->traceLevel = $value;
  140. }
  141. /**
  142. * @return integer how many messages should be logged before they are sent to targets.
  143. * This method returns the value of [[Logger::flushInterval]].
  144. */
  145. public function getFlushInterval()
  146. {
  147. return $this->getLogger()->flushInterval;
  148. }
  149. /**
  150. * @param integer $value how many messages should be logged before they are sent to targets.
  151. * This method will set the value of [[Logger::flushInterval]].
  152. * Defaults to 1000, meaning the [[Logger::flush()]] method will be invoked once every 1000 messages logged.
  153. * Set this property to be 0 if you don't want to flush messages until the application terminates.
  154. * This property mainly affects how much memory will be taken by the logged messages.
  155. * A smaller value means less memory, but will increase the execution time due to the overhead of [[Logger::flush()]].
  156. */
  157. public function setFlushInterval($value)
  158. {
  159. $this->getLogger()->flushInterval = $value;
  160. }
  161. /**
  162. * Dispatches the logged messages to [[targets]].
  163. * @param array $messages the logged messages
  164. * @param boolean $final whether this method is called at the end of the current application
  165. */
  166. public function dispatch($messages, $final)
  167. {
  168. $targetErrors = [];
  169. foreach ($this->targets as $target) {
  170. if ($target->enabled) {
  171. try {
  172. $target->collect($messages, $final);
  173. } catch (\Exception $e) {
  174. $target->enabled = false;
  175. $targetErrors[] = [
  176. 'Unable to send log via ' . get_class($target) . ': ' . ErrorHandler::convertExceptionToString($e),
  177. Logger::LEVEL_WARNING,
  178. __METHOD__,
  179. microtime(true),
  180. [],
  181. ];
  182. }
  183. }
  184. }
  185. if (!empty($targetErrors)) {
  186. $this->dispatch($targetErrors, true);
  187. }
  188. }
  189. }