Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Помогите с оптимизацией анализатора логов (https://javascript.ru/forum/misc/55321-pomogite-s-optimizaciejj-analizatora-logov.html)

switch001 23.04.2015 08:20

Помогите с оптимизацией анализатора логов
 
Добрый день, товарищи!

Решил таки запилить анализатор логов к нашей системе, делал в лоб. Анализатор состоит из двух частей: фронтэнд на JS, бэкэнд на PHP. Бэкэнд простой - десяток строк, читает заданное количество строк с конца файла лога и выдает во фронтэнд построчно в формате JSON. Там его подбирает скрипт, разбивает строки на интересующие части для последующей подсветки синтаксиса и фильтрации. Поясню на картинке:



т.е. строку разбиваем регулярными выражениями на SPANы, каждому - свой стиль. По производительности особых проблем в этом нету, 200 килобайтный блок обрабатывается пару секунд. Но и это не нужно т.к. лог будет загружаться небольшими порциями в 10..100 строк в процессе работы системы.

Проблема в другом. В верхней части видны кнопки, при нажатии на них выключаем или включаем отбражение каких либо SPAN либо строк целиком. Сделано все влоб:
function toggleDate() 
	{
		$('.rgDate').hide();
	}
	
	function toggleError() 
	{
		$('.rgError').toggle('');
	}
		
	function toggleWarning() 
	{
		$('.rgWarning').toggle('');
	}
		
	function toggleNotice() 
	{
		$('.rgNotice').toggle('');
	}
		
	function toggleDebug() 
	{
		$('.rgDebug').toggle('');
	}
		
	function toggleVerbose() 
	{
		$('.rgVerbose').toggle('');
	}


Однако даже на 200К файле выключение, например, поля с датой занимает секунд 30. Процессор причем у меня довольно мощный, 2.5 ггц Coreduo и 6 Гб памяти.

Посоветуйте, пожалуйста, методы оптимизации чтобы хотя бы 1..2 мегабайтный лог работал с приемлемой скоростью. Я думал может стоит хранить строки в массиве, а при выводе переформатировать и фильтровать все что надо. Изменились условия - снова фильтруем и форматируем. Но это как-то не православно чтоли ;)

tsigel 23.04.2015 10:55

сделайте странички и ограничение скажем в 100 записей на странице и все будет летать. Вы всеравно не сможете смотреть сразу на все строки своего мегобайтного лога.

switch001 23.04.2015 11:18

Так не подойдет. Там один звонок может растянуться во времени, за это время насыпется еще стопицот записей. Плюс поиск нужен полнотекстовый, браузерный. В общем 100 строк, даже 1000 это зачастую маловато.

switch001 23.04.2015 20:49

Сделал так: сохраняю все строки в массив, перед выводом хелпер очищаю, потом прохожу регэкспами массив и выдаю в DOM уже готовый HTML. так работает в сто раз быстрее. На фильтрацию уходит примерно от одной до трех секунд пот 2500 строк. Но хочется еще больше скорости ;)

laimas 24.04.2015 12:11

В смысле, в колонках таблиц либо убираются, либо добавляются элементы SPAN?

tsigel 24.04.2015 21:45

Уберите регулярку и будет быстрее.

switch001 24.04.2015 23:23

Цитата:

Сообщение от laimas (Сообщение 368037)
В смысле, в колонках таблиц либо убираются, либо добавляются элементы SPAN?

Таблиц нет, есть только DIV - строка целиком, и SPAN - элемент строки. И то и это с нужными стилями. Фильтровал просто JQuery запросами по стилям, получалось медленно. Перестраивать DOM заново в нужном виде гораздо быстрее.


Цитата:

Сообщение от tsigel
Уберите регулярку и будет быстрее.

без регулярных выражений - никак. Слишком сложно сделать процедурную обработку. В процессе работы это мешать не будет: лог будет подгружаться порциями по 10..100 строк, которые сразу же будут обрабатываться, на таких объемах это быстро.

Но мне не нравится что приходится читать логи. Хочу напрямую присоединяться к сервису и получать данные. Но как сделать это - ума не приложу. Через stdout|stdin врядли получится.

laimas 25.04.2015 06:25

Таблиц нет, есть только DIV - строка целиком, и SPAN - элемент строки.

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

switch001 25.04.2015 07:16

Цитата:

Сообщение от laimas (Сообщение 368140)
Таблиц нет, есть только DIV - строка целиком, и SPAN - элемент строки.

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

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

laimas 25.04.2015 07:58

Я думал сервер отдает структуру логов (разобранную рег. выражением), то есть согласно кнопкам - Date, Verbose, ... То есть это и есть колонки, тогда это табличные данные в любом случае.

jscripter 25.04.2015 11:35

switch001,
А жеквери убрать не пробовали?

js_js 25.04.2015 14:21

switch001,
<html>
<head>
<style>
span{display: block}
</style>

</head>
<body>

<button id="rgDate">date</button>
<button id="rgError">error</button>
<button id="rgWarning">warning</button>
<button id="rgNotice">notice</button>
<button id="rgDebug">debug</button>

<br>

<div id="wrapper">

<span class="rgDate">date</span>
<span class="rgError">error</span>
<span class="rgWarning">warning</span>
<span class="rgNotice">notice</span>
<span class="rgDebug">debug</span>
<span class="rgDate">date</span>
<span class="rgError">error</span>
<span class="rgWarning">warning</span>
<span class="rgNotice">notice</span>
<span class="rgDebug">debug</span>
<span class="rgDate">date</span>
<span class="rgError">error</span>
<span class="rgWarning">warning</span>
<span class="rgNotice">notice</span>
<span class="rgDebug">debug</span>

</div>



<script>

s=wrapper.innerHTML

fltr=function(){
 var re=new RegExp('<span class="'+this.id+'">[^>]+>', 'g')
 wrapper.innerHTML=s.match(re).join("")
}

;[].forEach.call(document.querySelectorAll("button"), function(b){b.onclick=fltr})


</script>
</body>
</html>

На файле 540кб на слабой машине, скорость менее секунды

switch001 25.04.2015 20:36

js-js: подход конечно интересный. И, сцуко, элегантный!!! Не сразу понял как работает. (да-да, я принадлежу "поколению Jquery")
Сейчас попробую на своих данных.

jscripter: вот и пытаюсь это сделать

switch001 25.04.2015 21:05

js-js: действительно работает быстро. В моем наборе данных отрабатывает за секунду, в то время как мой подход работает около трех секунд. Но есть минус: данные уничтожаются. Нужно стиль чтоли менять на невидимый.

fuckjava 25.04.2015 21:07

Цитата:

Сообщение от switch001
данные уничтожаются

С чего бы это?

switch001 25.04.2015 22:16

Цитата:

Сообщение от fuckjava (Сообщение 368261)
С чего бы это?

ну как бы из исходника это понятно. Кстати он не работал у меня, сделал так:
<button onclick="fltr('rgDialplan');">Dialplan</button>

<script type="text/javascript" charset="utf-8"> 


function fltr(fld)
{
	
	var s=document.getElementById('helper').innerHTML;
	var re=new RegExp('<span class="'+fld+'">[^>]+>', 'g');
	document.getElementById('helper').innerHTML=s.replace(re, "");
}

fuckjava 25.04.2015 22:27

Цитата:

Сообщение от switch001
var s=document.getElementById('helper').innerHTML;

Вынесите эту строку за ф-цию.

Странная у Вас "позиция". В переводе на русский: "у меня уничтожаются данные, потому что я их уничтожаю, как бы так сделать, чтобы я их перестал уничтожать?"

fuckjava 25.04.2015 22:29

Цитата:

Сообщение от switch001
Кстати он не работал у меня

Почему же тут работает?:) Чудеса, да и только.

switch001 26.04.2015 07:44

Цитата:

Сообщение от fuckjava (Сообщение 368275)
Почему же тут работает?:) Чудеса, да и только.

Вот такие чудеса. Это работает
document.getElementById('helper').innerHTML

а это не работает
helper.innerHTML


Цитата:

Сообщение от fuckjava (Сообщение 368274)
Странная у Вас "позиция".

моя позиция - гетеросексуальная. А по поводу данных: предложенная функция удаляет текст из DOM, если пользователь захочет включить отображение тех или иных элементов то у него это не получится. Другой недостаток подхода в том, что если пользователь забудет окно закрыть, то за некоторое время в DOM насыпет несколько десятков мегабайт текста со всеми вытекающими. Т.е. нужно как-то ограничивать размер. В случае если текст хранится в массиве построчно эта проблема решается проще.

Erolast 26.04.2015 11:04

Цитата:

Сделал так: сохраняю все строки в массив, перед выводом хелпер очищаю, потом прохожу регэкспами массив и выдаю в DOM уже готовый HTML. так работает в сто раз быстрее. На фильтрацию уходит примерно от одной до трех секунд пот 2500 строк. Но хочется еще больше скорости
Храни массив объектов вида {label, text}, где label - одно из debug/verbose/error/чотамеще, а text - уже распаршенный в html текст, при изменении условий фильтруй по метке и вставляй через innerHTML.
var logItems = [{
    label: "debug",
    text: "<span>10:05:00</span><span>some debug message</span>"
}, {
    label: "error",
    text: "<span>10:05:00</span><span>some error message</span>"
}]
//..

document.getElementById("wrapper").innerHTML = logItems.filter(function(item) {
    return checkedLabels.indexOf(item.label) != -1;
}.map(function(item) {
    return "<div class='log-item'>" + item + "</div>";
}).join();


А вообще, такие вещи делаются не вручную, а с помощью движков биндинга вроде реакта.

switch001 26.04.2015 13:50

Цитата:

Сообщение от Erolast (Сообщение 368310)
Храни массив объектов

Тогда придется хранить массив всего что находится в строке.

А вообще я еще предыдущий метод не внедрил ;)
но попробую. Метод с поиском по DOM регэкспами оказался не шибко гибким.

UPDATE: метод с массивом тоже оказался муторным. Дело в том что скрывать нужно не только строку целиком, но и ее элементы. Т.е. надо строку разбить на группу элементов со свойствами, потом их собирать... а в строке не все ведь подлежит "разбивке", это тоже нужно хранить. В общем оценил объем возни и забил. К тому же потом понадобится анализировать не одну строку, а группы строк, это планирую делать регэкспом уже по готовому тексту. Короче пока оставил как есть.

Может есть какой-то механизм, который привяжет к каждому найденному элементу функцию, которая в свою очередь будет реагировать на какое-то событие скрытия ?

Erolast 26.04.2015 15:45

Цитата:

Тогда придется хранить массив всего что находится в строке.
Зачем?

Цитата:

Метод с поиском по DOM регэкспами оказался не шибко гибким.
Искать по DOM вручную регулярными выражениями - это тот еще идиотизм. Для кого DOM API придуман?
$(".toggle-log-item").on("click", (checkbox) => {
    let logItems = doucment.getElementById("wrapper").getElementsByClassName(checkbox.name);
    
    for (let item of logItems) {
        checkbox.display.style = checkbox.checked;
    }
});


Ну и, да, переключатель лучше представлять как <input type=checkbox>, а не <button>.

switch001 26.04.2015 17:24

Цитата:

Сообщение от Erolast (Сообщение 368345)
Зачем?

Искать по DOM вручную регулярными выражениями - это тот еще идиотизм. Для кого DOM API придуман?

вы это своему коллеге говорите, не мне. Хотя факт на лицо: работает быстро.
Цитата:

Сообщение от Erolast (Сообщение 368345)
Ну и, да, переключатель лучше представлять как <input type=checkbox>, а не <button>.

спасибо, КЭП!!!

Erolast 26.04.2015 19:28

Цитата:

вы это своему коллеге говорите, не мне. Хотя факт на лицо: работает быстро.
Ему что-то говорить бессмысленно - уже пытались сотню раз, я тебя предостерегаю.

Цитата:

спасибо, КЭП!!!
Хм, почему-то показалось, что у тебя button была.
Но зачем так грубо отвечать? Я, вообще-то, помочь пытаюсь.

switch001 26.04.2015 19:56

Цитата:

Сообщение от Erolast (Сообщение 368361)
Ему что-то говорить бессмысленно - уже пытались сотню раз, я тебя предостерегаю.

я соглашусь что его метод, мягко говоря, странный. Однако он работает. И работает быстро. Могу лишь сказать что мир бы увидел Doom или Wolfenstein намного позже ежели Джон Кармак пользовался бы исключительно очевидными и "правильными" методами. Конечно сейчас оптимизацией почти никто не занимается. Многие даже думать в этом направлении не умеют. А я застал те времена, когда особо критичные вещи писали на ассемблере. Хорошо что они прошли нахрен ;)
Цитата:

Сообщение от Erolast (Сообщение 368361)
Хм, почему-то показалось, что у тебя button была.
Но зачем так грубо отвечать? Я, вообще-то, помочь пытаюсь.

Извините, если обидел. Но вроде не грубо ответил.
button была. Я марафет еще не наводил, а налепил чтоб было на что нажать, только и всего. Ща вот никак из unix сокета не могу этот лог прочитать, немного подзабил на отображение.

Erolast 26.04.2015 20:09

Цитата:

я соглашусь что его метод, мягко говоря, странный. Однако он работает. И работает быстро
Медленнее, чем нормальный вариант через DOM API.

Цитата:

Могу лишь сказать что мир бы увидел Doom или Wolfenstein намного позже ежели Джон Кармак пользовался бы исключительно очевидными и "правильными" методами.
Одно дело - когда хак оправдан, другое - когда правильный метод выигрывает во всех отношениях.


Часовой пояс GMT +3, время: 16:53.