diff options
Diffstat (limited to 'library/Icinga/Protocol/File/LogFileIterator.php')
-rw-r--r-- | library/Icinga/Protocol/File/LogFileIterator.php | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/library/Icinga/Protocol/File/LogFileIterator.php b/library/Icinga/Protocol/File/LogFileIterator.php new file mode 100644 index 0000000..67a4d99 --- /dev/null +++ b/library/Icinga/Protocol/File/LogFileIterator.php @@ -0,0 +1,149 @@ +<?php +/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */ + +namespace Icinga\Protocol\File; + +use Icinga\Exception\IcingaException; +use SplFileObject; +use Iterator; + +/** + * Iterate over a log file, yielding the regex fields of the log messages + */ +class LogFileIterator implements Iterator +{ + /** + * Log file + * + * @var SplFileObject + */ + protected $file; + + /** + * A PCRE string with the fields to extract + * from the log messages as named subpatterns + * + * @var string + */ + protected $fields; + + /** + * Value for static::current() + * + * @var array + */ + protected $current; + + /** + * Index for static::key() + * + * @var int + */ + protected $index; + + /** + * Value for static::valid() + * + * @var boolean + */ + protected $valid; + + /** + * @var string + */ + protected $next = null; + + /** + * @param string $filename The log file's name + * @param string $fields A PCRE string with the fields to extract + * from the log messages as named subpatterns + */ + public function __construct($filename, $fields) + { + $this->file = new SplFileObject($filename); + $this->file->setFlags( + SplFileObject::DROP_NEW_LINE | + SplFileObject::READ_AHEAD + ); + $this->fields = $fields; + } + + public function rewind(): void + { + $this->file->rewind(); + $this->index = 0; + $this->nextMessage(); + } + + public function next(): void + { + $this->file->next(); + ++$this->index; + $this->nextMessage(); + } + + public function current(): array + { + return $this->current; + } + + public function key(): int + { + return $this->index; + } + + public function valid(): bool + { + return $this->valid; + } + + protected function nextMessage() + { + $message = $this->next === null ? array() : array($this->next); + $this->valid = null; + while ($this->file->valid()) { + if (false === ($res = preg_match( + $this->fields, + $current = $this->file->current() + ))) { + throw new IcingaException('Failed at preg_match()'); + } + if (empty($message)) { + if ($res === 1) { + $message[] = $current; + } + } elseif ($res === 1) { + $this->next = $current; + $this->valid = true; + break; + } else { + $message[] = $current; + } + + $this->file->next(); + } + if ($this->valid === null) { + $this->next = null; + $this->valid = ! empty($message); + } + + if ($this->valid) { + while (! empty($message)) { + $matches = array(); + if (false === ($res = preg_match( + $this->fields, + implode(PHP_EOL, $message), + $matches + ))) { + throw new IcingaException('Failed at preg_match()'); + } + if ($res === 1) { + $this->current = $matches; + return; + } + array_pop($message); + } + $this->valid = false; + } + } +} |