您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

162 行
6.0KB

  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\InvalidConfigException;
  10. use yii\helpers\FileHelper;
  11. /**
  12. * FileTarget records log messages in a file.
  13. *
  14. * The log file is specified via [[logFile]]. If the size of the log file exceeds
  15. * [[maxFileSize]] (in kilo-bytes), a rotation will be performed, which renames
  16. * the current log file by suffixing the file name with '.1'. All existing log
  17. * files are moved backwards by one place, i.e., '.2' to '.3', '.1' to '.2', and so on.
  18. * The property [[maxLogFiles]] specifies how many history files to keep.
  19. *
  20. * @author Qiang Xue <qiang.xue@gmail.com>
  21. * @since 2.0
  22. */
  23. class FileTarget extends Target
  24. {
  25. /**
  26. * @var string log file path or path alias. If not set, it will use the "@runtime/logs/app.log" file.
  27. * The directory containing the log files will be automatically created if not existing.
  28. */
  29. public $logFile;
  30. /**
  31. * @var bool whether log files should be rotated when they reach a certain [[maxFileSize|maximum size]].
  32. * Log rotation is enabled by default. This property allows you to disable it, when you have configured
  33. * an external tools for log rotation on your server.
  34. * @since 2.0.3
  35. */
  36. public $enableRotation = true;
  37. /**
  38. * @var integer maximum log file size, in kilo-bytes. Defaults to 10240, meaning 10MB.
  39. */
  40. public $maxFileSize = 10240; // in KB
  41. /**
  42. * @var integer number of log files used for rotation. Defaults to 5.
  43. */
  44. public $maxLogFiles = 5;
  45. /**
  46. * @var integer the permission to be set for newly created log files.
  47. * This value will be used by PHP chmod() function. No umask will be applied.
  48. * If not set, the permission will be determined by the current environment.
  49. */
  50. public $fileMode;
  51. /**
  52. * @var integer the permission to be set for newly created directories.
  53. * This value will be used by PHP chmod() function. No umask will be applied.
  54. * Defaults to 0775, meaning the directory is read-writable by owner and group,
  55. * but read-only for other users.
  56. */
  57. public $dirMode = 0775;
  58. /**
  59. * @var boolean Whether to rotate log files by copy and truncate in contrast to rotation by
  60. * renaming files. Defaults to `true` to be more compatible with log tailers and is windows
  61. * systems which do not play well with rename on open files. Rotation by renaming however is
  62. * a bit faster.
  63. *
  64. * The problem with windows systems where the [rename()](http://www.php.net/manual/en/function.rename.php)
  65. * function does not work with files that are opened by some process is described in a
  66. * [comment by Martin Pelletier](http://www.php.net/manual/en/function.rename.php#102274) in
  67. * the PHP documentation. By setting rotateByCopy to `true` you can work
  68. * around this problem.
  69. */
  70. public $rotateByCopy = true;
  71. /**
  72. * Initializes the route.
  73. * This method is invoked after the route is created by the route manager.
  74. */
  75. public function init()
  76. {
  77. parent::init();
  78. if ($this->logFile === null) {
  79. $this->logFile = Yii::$app->getRuntimePath() . '/logs/app.log';
  80. } else {
  81. $this->logFile = Yii::getAlias($this->logFile);
  82. }
  83. $logPath = dirname($this->logFile);
  84. if (!is_dir($logPath)) {
  85. FileHelper::createDirectory($logPath, $this->dirMode, true);
  86. }
  87. if ($this->maxLogFiles < 1) {
  88. $this->maxLogFiles = 1;
  89. }
  90. if ($this->maxFileSize < 1) {
  91. $this->maxFileSize = 1;
  92. }
  93. }
  94. /**
  95. * Writes log messages to a file.
  96. * @throws InvalidConfigException if unable to open the log file for writing
  97. */
  98. public function export()
  99. {
  100. $text = implode("\n", array_map([$this, 'formatMessage'], $this->messages)) . "\n";
  101. if (($fp = @fopen($this->logFile, 'a')) === false) {
  102. throw new InvalidConfigException("Unable to append to log file: {$this->logFile}");
  103. }
  104. @flock($fp, LOCK_EX);
  105. if ($this->enableRotation) {
  106. // clear stat cache to ensure getting the real current file size and not a cached one
  107. // this may result in rotating twice when cached file size is used on subsequent calls
  108. clearstatcache();
  109. }
  110. if ($this->enableRotation && @filesize($this->logFile) > $this->maxFileSize * 1024) {
  111. $this->rotateFiles();
  112. @flock($fp, LOCK_UN);
  113. @fclose($fp);
  114. @file_put_contents($this->logFile, $text, FILE_APPEND | LOCK_EX);
  115. } else {
  116. @fwrite($fp, $text);
  117. @flock($fp, LOCK_UN);
  118. @fclose($fp);
  119. }
  120. if ($this->fileMode !== null) {
  121. @chmod($this->logFile, $this->fileMode);
  122. }
  123. }
  124. /**
  125. * Rotates log files.
  126. */
  127. protected function rotateFiles()
  128. {
  129. $file = $this->logFile;
  130. for ($i = $this->maxLogFiles; $i >= 0; --$i) {
  131. // $i == 0 is the original log file
  132. $rotateFile = $file . ($i === 0 ? '' : '.' . $i);
  133. if (is_file($rotateFile)) {
  134. // suppress errors because it's possible multiple processes enter into this section
  135. if ($i === $this->maxLogFiles) {
  136. @unlink($rotateFile);
  137. } else {
  138. if ($this->rotateByCopy) {
  139. @copy($rotateFile, $file . '.' . ($i + 1));
  140. if ($fp = @fopen($rotateFile, 'a')) {
  141. @ftruncate($fp, 0);
  142. @fclose($fp);
  143. }
  144. if ($this->fileMode !== null) {
  145. @chmod($file . '.' . ($i + 1), $this->fileMode);
  146. }
  147. } else {
  148. @rename($rotateFile, $file . '.' . ($i + 1));
  149. }
  150. }
  151. }
  152. }
  153. }
  154. }