Отфильтровано чтения журнала


Я разработал чтения журнала, который может фильтровать то, что она вывела несколько следующих критериев: значение errorlevel, продукт, категория, код. Он работает, но когда лог-файл действительно большой, она становится очень медленной, на грани выхода за предел времени.

log_reader.php

<?php
    session_start();
    unset($_SESSION['errorlevel']);
    unset($_SESSION['category']);
    unset($_SESSION['product']);
    unset($_SESSION['id']);
    $lines = file("error.log");
    $categories = array();
    $products = array();
    $ids = array();
    foreach($lines as $line){
        $segments = explode("][",substr($line,1,strrpos($line,']')-1));
        if((!in_array($segments[2],$categories))&&(!empty($segments[2]))){
            $categories[] = $segments[2];
        }
        if((!in_array($segments[3],$products))&&(!empty($segments[3]))){
            $products[] = $segments[3];
        }
        if((!in_array($segments[4],$ids))&&(!empty($segments[4]))){
            $ids[] = $segments[4];
        }
    }
    sort($categories);
    sort($products);
    sort($ids);
?>

<html>
  <head>
    <title>Log Reader</title>
    <link rel="stylesheet" type="text/css" href="style.css" />
    <script type="text/javascript">
      function showHide(selection){
          var name = selection.name;
          var opt = selection.options[selection.selectedIndex].value;
          if (window.XMLHttpRequest){ 
              //code for IE7+, Firefox, Chrome, Opera, Safari 
              xmlhttp=new XMLHttpRequest(); 
          }else{ 
              // code for IE6, IE5 
              xmlhttp=new ActiveXObject('Microsoft.XMLHTTP'); 
          }
          xmlhttp.onreadystatechange=function(){ 
              if (xmlhttp.readyState==4 && xmlhttp.status==200){

                  document.getElementById('logterminal').innerHTML=xmlhttp.responseText; 
              } 
          }
          xmlhttp.open('GET', 'filteredlog.php?'+name+'='+opt, true); 
          xmlhttp.send();
          return false; 
      }
    </script>
  </head>
  <body>
    <div style="background-color:#fffacd;">
      <form>
        <select name="errorlevel" onchange="return showHide(this);">
          <option value="DEBUG">DEBUG</option>
          <option value="INFO" selected="selected">INFO</option>
          <option value="WARN">WARN</option>
          <option value="ERROR">ERROR</option>
        </select>
        <select name="category" onchange="return showHide(this);">
          <option value="All">All Categories</option>
          <?php
            foreach($categories as $category){
                echo "<option value='".$category."'>".$category."</option>";
            }
          ?>
        </select>
        <select name="product" onchange="return showHide(this);">
          <option value="All">All Products</option>
          <?php
            foreach($products as $product){
                echo "<option value='".$product."'>".$product."</option>";
            }
          ?>
        </select>
        <select name="id" onchange="return showHide(this);">
          <option value="All">All IDs</option>
          <?php
            foreach($ids as $id){
                echo "<option value='".$id."'>".$id."</option>";
            }
          ?>
        </select>
      </form>
    </div>
    <div id="logterminal">
    <?php
        include("filteredlog.php");
    ?>
    </div>
  </body>
</html>

filteredlog.php

<?php
if(count(debug_backtrace())==0){;
    session_start();
}
$errorlevel = $_GET['errorlevel'];
$errorlevels = array("DEBUG", "INFO", "WARN", "ERROR");
if(empty($errorlevel)){
    if(isset($_SESSION['errorlevel'])){
        $errorlevel = $_SESSION['errorlevel'];
    }else{
        $errorlevel = "INFO";
    }
}else{
    $_SESSION['errorlevel']=$errorlevel;
}

$category = $_GET['category'];
if(empty($category)){
    if(isset($_SESSION['category'])){
        $category = $_SESSION['category'];
    }else{
        $category = "All";
    }
}else{
    $_SESSION['category']=$category;
}

$product = $_GET['product'];
if(empty($product)){
    if(isset($_SESSION['product'])){
        $product = $_SESSION['product'];
    }else{
        $product = "All";
    }
}else{
    $_SESSION['product']=$product;
}

$id = $_GET['id'];
if(empty($id)){
    if(isset($_SESSION['id'])){
        $id = $_SESSION['id'];
    }else{
        $id = "All";
    }
}else{
    $_SESSION['id']=$id;
}

$lines = file("error.log");
$categories = array();
$products = array();
$ids = array();
foreach($lines as $line){
    $segments = explode("][",substr($line,1,strrpos($line,']')-1));
    if((!in_array($segments[2],$categories))&&(!empty($segments[2]))){
        $categories[] = $segments[2];
    }
    if((!in_array($segments[3],$products))&&(!empty($segments[3]))){
        $products[] = $segments[3];
    }
    if((!in_array($segments[4],$ids))&&(!empty($segments[4]))){
        $ids[] = $segments[4];
    }
}

echo $errorlevel . $category . $product . $id . "<br /><br />";


$currentlvl = "";
$filterlines = array();
foreach($lines as $line){
    $segments = explode("][",substr($line,1,strrpos($line,']')-1));
    $line_errlvl = $segments[0];
    if(!in_array($line_errlvl,$errorlevels)){
        $line_errlvl = $currentlvl;
    }
    switch($errorlevel){
        case "DEBUG":
            if($line_errlvl=="DEBUG"){
                $filterlines[] = $line;
            }
        case "INFO":
            if($line_errlvl=="INFO"){
                $filterlines[] = $line;
            }
        case "WARN":
            if($line_errlvl=="WARN"){
                $filterlines[] = $line;

            }
        case "ERROR":
            if($line_errlvl=="ERROR"){
                $filterlines[] = $line;
            }
        default:
            $currentlvl = $line_errlvl;
            break;
    }
}
if($product != "All"){
    $lines = $filterlines;
    $currentcat = "";
    $filterlines = array();
    foreach($lines as $line){
        $segments = explode("][",substr($line,1,strrpos($line,']')-1));
        $line_cat = $segments[2];
        if(!in_array($line_cat,$categories)){
            $line_cat = $currentcat;
        }
        if($line_cat==$category){
           $filterlines[] = $line;
        }
        $currentcat = $line_cat;
    }
}
if($product != "All"){
    $lines = $filterlines;
    $currentprod = "";
    $filterlines = array();
    foreach($lines as $line){
        $segments = explode("][",substr($line,1,strrpos($line,']')-1));
        $line_prod = $segments[3];
        if(!in_array($line_prod,$releases)){
            $line_prod = $currentprod;
        }
        if($line_prod==$product){
           $filterlines[] = $line;
        }
        $currentprod = $line_prod;
    }
}
if($id != "All"){
    $lines = $filterlines;
    $currentid = "";
    $filterlines = array();
    foreach($lines as $line){
        $segments = explode("][",substr($line,1,strrpos($line,']')-1));
        $line_id = $segments[4];
        if(!in_array($line_id,$ids)){
            $line_id = $currentid;
        }
        if($line_id==$id){
           $filterlines[] = $line;
        }
        $currentid = $line_id;
    }
}

foreach($filterlines as $line){
    echo $line . "<br />";
}

?>


187
2
задан 20 сентября 2011 в 07:09 Источник Поделиться
Комментарии
2 ответа

Я бы не сказал, что это повлияет на вашу производительность значительно, но обычно если((!in_array($сегментах[4],$ИД))&&(!пустой($сегментах[4])))
Написано как если(!пустой($сегментах[4])&&!in_array($сегментах[4],$ИД)) с тем, чтобы, если элемент является пустым.

2
ответ дан 22 сентября 2011 в 03:09 Источник Поделиться

Ну, если у вас есть продукт, идентификатор и категория "все" (или эквивалент), то ваш скрипт вызывает:

$segments = explode("][",substr($line,1,strrpos($line,']')-1));

НА КАЖДОЙ СТРОКЕ ФАЙЛА, В ПЯТЬ РАЗ.

Считаю, вместо:

$segs = array();
foreach($lines as $line){
$segments = explode("][",substr($line,1,strrpos($line,']')-1));
$segs[] = $segments;
// then continue modifying/filtering the processed data instead of the strings

Этот блок создает ряд переменных, которые не используются больше нигде. Я рекомендую прерывая его:

$categories = array();
$products = array();
$ids = array();
foreach($lines as $line){
$segments = explode("][",substr($line,1,strrpos($line,']')-1));
if((!in_array($segments[2],$categories))&&(!empty($segments[2]))){
$categories[] = $segments[2];
}
if((!in_array($segments[3],$products))&&(!empty($segments[3]))){
$products[] = $segments[3];
}
if((!in_array($segments[4],$ids))&&(!empty($segments[4]))){
$ids[] = $segments[4];
}
}

Как правило, тест, чтобы увидеть, если индекс массива существует, прежде чем использовать его тоже, но после того, как вы избавились от этого блока, вам не придется беспокоиться о том, что этот тип массива, поиск происходит только там.

Более тонкий момент:

// this was foreach($lines as $line){, but I am assuming the fix suggested earlier.
foreach($segs as $segments){
$line_errlvl = $segments[0];
if(!in_array($line_errlvl,$errorlevels)){
$line_errlvl = $currentlvl;
}
switch($errorlevel){
case "DEBUG":
if($line_errlvl=="DEBUG"){
$filterlines[] = $line;
}//...

Так, in_array выполняет простой поиск в массиве и возвращает true или false. Если, однако, мы изменим это на array_search мы могли бы использовать < оператор. Рассмотрим:

$numericLevel = array_search($errorlevel, $errorlevels);
$currentlvl = 0;
$filterlines = array();
foreach($segs as $idx => $segments){
// in_array basically does the same thing (on the machine level),
// only it is less useful here.
$line_errlvl = array_search($segments[0], $errorlevels);
if(FALSE === $line_errlvl) $line_errlvl = $currentlvl;
if($line_errlvl >= $numericLevel) $filterlines[] = $lines[$idx];
$currentlvl = $line_errlvl;
}

Что будет в будущем ваш код (вы можете добавить в журнале "скунс" позже, и он все равно будет работать), и это также делает его более эффективным ... если вы были созданы, чтобы "отладить" и побежал оригинал:

switch($errorlevel){
case "DEBUG":

Вы бы в конечном итоге сравнивая строки отладки информация, предупредить, и ошибка. Это делает точно одно сравнение.



Лично я тоже считаю, что это не где вы хотите быть через сессий. Это должна быть серия читает, это действительно не имеет смысла хранить его.

0
ответ дан 22 сентября 2011 в 04:09 Источник Поделиться