FileTarget.php 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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 files to keep.
  19. *
  20. * @author Qiang Xue <[email protected]>
  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 integer maximum log file size, in kilo-bytes. Defaults to 10240, meaning 10MB.
  32. */
  33. public $maxFileSize = 10240; // in KB
  34. /**
  35. * @var integer number of log files used for rotation. Defaults to 5.
  36. */
  37. public $maxLogFiles = 5;
  38. /**
  39. * @var integer the permission to be set for newly created log files.
  40. * This value will be used by PHP chmod() function. No umask will be applied.
  41. * If not set, the permission will be determined by the current environment.
  42. */
  43. public $fileMode;
  44. /**
  45. * @var integer the permission to be set for newly created directories.
  46. * This value will be used by PHP chmod() function. No umask will be applied.
  47. * Defaults to 0775, meaning the directory is read-writable by owner and group,
  48. * but read-only for other users.
  49. */
  50. public $dirMode = 0775;
  51. /**
  52. * Initializes the route.
  53. * This method is invoked after the route is created by the route manager.
  54. */
  55. public function init()
  56. {
  57. parent::init();
  58. if ($this->logFile === null) {
  59. $this->logFile = Yii::$app->getRuntimePath() . '/logs/app.log';
  60. } else {
  61. $this->logFile = Yii::getAlias($this->logFile);
  62. }
  63. $logPath = dirname($this->logFile);
  64. if (!is_dir($logPath)) {
  65. FileHelper::createDirectory($logPath, $this->dirMode, true);
  66. }
  67. if ($this->maxLogFiles < 1) {
  68. $this->maxLogFiles = 1;
  69. }
  70. if ($this->maxFileSize < 1) {
  71. $this->maxFileSize = 1;
  72. }
  73. }
  74. /**
  75. * Writes log messages to a file.
  76. * @throws InvalidConfigException if unable to open the log file for writing
  77. */
  78. public function export()
  79. {
  80. $text = implode("\n", array_map([$this, 'formatMessage'], $this->messages)) . "\n";
  81. if (($fp = @fopen($this->logFile, 'a')) === false) {
  82. throw new InvalidConfigException("Unable to append to log file: {$this->logFile}");
  83. }
  84. @flock($fp, LOCK_EX);
  85. if (@filesize($this->logFile) > $this->maxFileSize * 1024) {
  86. $this->rotateFiles();
  87. @flock($fp, LOCK_UN);
  88. @fclose($fp);
  89. @file_put_contents($this->logFile, $text, FILE_APPEND | LOCK_EX);
  90. } else {
  91. @fwrite($fp, $text);
  92. @flock($fp, LOCK_UN);
  93. @fclose($fp);
  94. }
  95. if ($this->fileMode !== null) {
  96. @chmod($this->logFile, $this->fileMode);
  97. }
  98. }
  99. /**
  100. * Rotates log files.
  101. */
  102. protected function rotateFiles()
  103. {
  104. $file = $this->logFile;
  105. for ($i = $this->maxLogFiles; $i > 0; --$i) {
  106. $rotateFile = $file . '.' . $i;
  107. if (is_file($rotateFile)) {
  108. // suppress errors because it's possible multiple processes enter into this section
  109. if ($i === $this->maxLogFiles) {
  110. @unlink($rotateFile);
  111. } else {
  112. @rename($rotateFile, $file . '.' . ($i + 1));
  113. }
  114. }
  115. }
  116. if (is_file($file)) {
  117. @rename($file, $file . '.1'); // suppress errors because it's possible multiple processes enter into this section
  118. }
  119. }
  120. }