RotatingFileHandler.php 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. <?php
  2. /*
  3. * This file is part of the Monolog package.
  4. *
  5. * (c) Jordi Boggiano <j.boggiano@seld.be>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Monolog\Handler;
  11. use Monolog\Logger;
  12. /**
  13. * Stores logs to files that are rotated every day and a limited number of files are kept.
  14. *
  15. * This rotation is only intended to be used as a workaround. Using logrotate to
  16. * handle the rotation is strongly encouraged when you can use it.
  17. *
  18. * @author Christophe Coevoet <stof@notk.org>
  19. */
  20. class RotatingFileHandler extends StreamHandler
  21. {
  22. protected $filename;
  23. protected $maxFiles;
  24. protected $mustRotate;
  25. /**
  26. * @param string $filename
  27. * @param integer $maxFiles The maximal amount of files to keep (0 means unlimited)
  28. * @param integer $level The minimum logging level at which this handler will be triggered
  29. * @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
  30. */
  31. public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true)
  32. {
  33. $this->filename = $filename;
  34. $this->maxFiles = (int) $maxFiles;
  35. $fileInfo = pathinfo($this->filename);
  36. $timedFilename = $fileInfo['dirname'].'/'.$fileInfo['filename'].'-'.date('Y-m-d');
  37. if (!empty($fileInfo['extension'])) {
  38. $timedFilename .= '.'.$fileInfo['extension'];
  39. }
  40. // disable rotation upfront if files are unlimited
  41. if (0 === $this->maxFiles) {
  42. $this->mustRotate = false;
  43. }
  44. parent::__construct($timedFilename, $level, $bubble);
  45. }
  46. /**
  47. * {@inheritdoc}
  48. */
  49. public function close()
  50. {
  51. parent::close();
  52. if (true === $this->mustRotate) {
  53. $this->rotate();
  54. }
  55. }
  56. /**
  57. * {@inheritdoc}
  58. */
  59. protected function write(array $record)
  60. {
  61. // on the first record written, if the log is new, we should rotate (once per day)
  62. if (null === $this->mustRotate) {
  63. $this->mustRotate = !file_exists($this->url);
  64. }
  65. parent::write($record);
  66. }
  67. /**
  68. * Rotates the files.
  69. */
  70. protected function rotate()
  71. {
  72. $fileInfo = pathinfo($this->filename);
  73. $glob = $fileInfo['dirname'].'/'.$fileInfo['filename'].'-*';
  74. if (!empty($fileInfo['extension'])) {
  75. $glob .= '.'.$fileInfo['extension'];
  76. }
  77. $iterator = new \GlobIterator($glob);
  78. $count = $iterator->count();
  79. if ($this->maxFiles >= $count) {
  80. // no files to remove
  81. return;
  82. }
  83. // Sorting the files by name to remove the older ones
  84. $array = iterator_to_array($iterator);
  85. usort($array, function($a, $b) {
  86. return strcmp($b->getFilename(), $a->getFilename());
  87. });
  88. foreach (array_slice($array, $this->maxFiles) as $file) {
  89. if ($file->isWritable()) {
  90. unlink($file->getRealPath());
  91. }
  92. }
  93. }
  94. }