Gnuplot — малюємо час на отримання результату від Informix’а

Posted on

Є Asterisk, через який дзвонить купа клієнтів. Є задача — отримати від сервера Informix (не питайте, бо не знаю) кількість секунд, які певний клієнт може наговорити, дзвонячи на певний номер телефону. Тобто, для спрощення, на сервер іде запит [номерА, номерБ], сервер віддає число (>=0).

При цьому є підозра, що під кінець місяця сервер думатиме довше; є також підозра, що ті клієнти, що більше говорять, довше чекатимуть відповіді.

Хочеться це все якось бачити. Для цього у той скрипт, який бере дані з Informix’а, додаємо двійко рядків, щоб писати журнал, у приблизно такому вигляді:

# час, «номер клієнта», куди дзвонив, залишок секунд, час на отримання
# звісно, всі номери <номерБ> різні:
"2012-04-05 17:29:34.455199","01",<номерБ>",0,"0:00:00.078631"
"2012-04-05 17:46:47.482675","02",<номерБ>",0,"0:00:00.895389"
"2012-04-05 17:48:19.594244","02",<номерБ>",0,"0:00:00.029423"
"2012-04-05 17:53:18.827345","02",<номерБ>",0,"0:00:00.033318"
"2012-04-05 18:02:59.955417","02",<номерБ>",0,"0:00:00.042353"
"2012-04-05 18:05:10.750765","02",<номерБ>",0,"0:00:00.031215"
"2012-04-05 18:05:53.240702","02",<номерБ>",0,"0:00:00.029587"
"2012-04-05 18:06:47.190297","03",<номерБ>",0,"0:00:00.063169"
"2012-04-05 18:56:49.293827","02",<номерБ>",0,"0:00:01.110830"
"2012-04-05 19:03:51.475956","02",<номерБ>",0,"0:00:00.032815"
"2012-04-05 19:42:59.389716","02",<номерБ>",0,"0:00:00.034776"

Так, зараз на всі запити сервер віддає нуль, не зважайте .)

Зверніть також увагу, що у журнал падає, насправді, не 01, 02, 03 тощо, а номер телефону, з якого йшла спроба дзвонити, — але я ховаю номер телефону, ховатиму його й на графіку, і у скрипті нижче для цього буде вжито певних заходів (тобто, це робитиму не я, а awk). Тобто, замість номеру телефону awk підставлятиме «номер клієнта».

На графіку хочемо бачити щось таке (по координаті X буде час):

  • червоними хрестиками — час відгуку;
  • синіми колами — час від попереднього дзвінка;
  • для відгуків > 0.5 секунди біля хрестика писатимемо клієнта;
  • і ще якісь усереднення.

Я нижче поясню, чому це не надто ілюстративно для даної задачі, і що варто було б зробити натомість, але — нижче.

Щоб малювати час від попереднього запиту нам мало цих даних — до кожного рядка треба також додати це значення.

Отже, цей скрипт тягне журнал з іншого сервера, прибирає лапки, додає до кожного рядка різницю між часом запису цього рядка (перше поле у журналі) і часом запису попереднього, замість номерів телефонів клієнтів пише абстрактний «номер клієнта» (кожному наступному номеру телефону — який ще не траплявся — дає наступний порядковий номер) і записує «скрипт» для Gnuplot’а.

#
 
workdir=`/usr/bin/dirname $0`
 
cd $workdir
 
remote="getAvailSeconds.log"
filein="getAvailSeconds-in.log"
fileout="getAvailSeconds-out.log"
 
plotfile="getAvailSeconds.plot"
pdffile="getAvailSeconds.pdf"
 
server="laip"
 
/usr/bin/scp ${server}:"/tmp/${remote}" "${filein}"
 
/bin/cat "$filein" \
    | /usr/bin/awk '
        BEGIN {
            # на вході маємо розділені комами поля:
            FS=","
        } {
            # видаляємо подвійні лапки:
            gsub(/\"/,"",$0);
            # видаляємо години і хвилини, лишаємо лише секунди:
            gsub(/^0:00:0*/,"",$5);
            # беремо час запису з $1 (ігноруємо долі секунди)
            # (при цьому, до речі, $1 не міняється ж!):
            time = mktime(gensub("[-:]", " ", "g", substr($1,0,19)));
            # для *най*першого рядка --- немає часу попереднього запису:
            if( !oldtime ) { oldtime = time; };
            # якщо цього номеру телефону ще не було ---
            # додаємо у хеш рядок "<наступний_номер>":
            if ( ! ($2 in clients) ) {
                clients[$2] = sprintf("%02d", (length(clients) + 1));
            }
            # друкуємо журнал, з якого малюватимемо gnuplot’ом:
            print $1, clients[$2], $3, $4, $5, (time - oldtime);
            # запам’ятовуємо час запису:
            oldtime = time;
        }'  > "$fileout"

Це лише перша частина — витягування і переформатовування журналу.

Далі створимо «скрипт» для gnuplot’а — можна було б і без окремого файлу, але він нам може згодитися і як окремий файл. Можливо .)

## за останній місцяць?
# start=`date +"%Y-%m-%d %H:%M" --date="1 month ago"`
# ні, з моменту, коли почали збирати статистику ,)
start="2012-04-05 00:00"
end=`/bin/date +"%Y-%m-%d %H:%M" --date="6 hours"`
now=`/bin/date +"%Y-%m-%d %H:%M"`
 
/bin/cat <<PLOT > "$plotfile"
set title "Time to get data from Informix"
set grid
set xdata time
# це для визначення діапазону часу по X:
set timefmt "%Y-%m-%d %H:%M"
set xrange ["$start":"$end"]
set yrange [0:]
set ylabel "seconds"
 
# ми будемо використовувати "enhanced" вихідний формат,
# тому можемо масштабувати мітки ("/=4" --- коефіцієнт):
set format x "{/=4 %d/%m/%y %H:%M}"
 
set ytics out nomirror
# повернемо і трохи опустимо мітки шкали часу:
set xtics rotate by 90 out offset 0.3,-4.3 nomirror scale 1.5
 
# а це описуємо формат часу у файлі з даними:
set timefmt "%Y-%m-%d %H:%M:%S"
 
set term pdfcairo enhanced size 8in,5in
set output "$pdffile"
 
set tmargin 4; set bmargin 8; set lmargin 11; set rmargin 3
 
set key left
 
## for 8in,5in:
# трохи опускаємо «номери клієнтів» для відгуків, коротших за 1 секунду,
# і трохи піднімаємо для триваліших запитів (див. графік нижче):
yoff(y) = (y<1.0) ? (y - 0.07) : (y + 0.02)
# ставитимемо на графіку «номер клієнта» лише для запитів,
# що чекали довше 0.5 секунди:
get_label(y,numA) = (y>0.5)?sprintf("{/=%f client%02i}", 4, numA):""
 
set arrow from "$now", graph 0 to "$now", graph 1 nohead lc rgb "gray70"
 
# намалюємо два «усереднення», з різними коефіцієнтами:
w1 = 1e-13
w2 = 1e-15
 
plot "$fileout" \\
        using 1:6:7 \\
        with circles lc rgb "royalblue" title "", \\
     "" using 1:6 lc rgb "red" title "", \\
     "" using 1:6:(w1) smooth acsplines title sprintf("w: %1.0e", w1) \\
        lc rgb "orange", \\
     "" using 1:6:(w2) smooth acsplines title sprintf("w: %1.0e", w2) \\
        lc rgb "dark-olivegreen", \\
     "" using 1:(yoff(\$6)):(get_label(\$6,\$3)) \\
        with labels title ""
PLOT

Тут забагато backslash’ів — це тому, що ми виводимо у файл.

От і все, малюємо:

/usr/bin/gnuplot "${plotfile}"

І маємо отакий (на от зараз) результат! Маємо у PDF, але я сконвертував, щоб вставити у сторінку:

Це не ілюстративно? Чому?

Так, це не ілюстративно, бо ми не бачимо, чи характерні для цих певних клієнтів отакі певні «викиди». Тобто, якийсь клієнт може подзвонити (спробувати подзвонити) раз у житті, але на сервері було саме щось негаразд, він чекав три секунди.

Тому ці всі «усереднення» з різними ваговими коефіцієнтами — це «середня температура по лікарні» .)

Значно цікавіше було б малювати не всіх клієнтів червоними хрестиками, а кожного клієнта малювати окремо… Наприклад, час від попереднього запиту малювати горизонтальною рискою вліво, а середньоквадратичне відхилення для даного клієнта малювати колом (з радіусом, що дорівнює цьому СКВ)… Але що нам заважає?-)

Ми дуже просто можемо модифікувати наш awk’овий скрипт:

            # ...
            # пишемо для кожного клієнта «його власний» файл із даними:
            print $1, clients[$2], $3, $4, $5, (time - oldtime) > sprintf("client%02s.data", clients[$2]);
            # запам’ятовуємо час запису:
            oldtime = time;
        }
        END {
            # після завершення роботи пишемо перелік клієнтів:
            for ( val in clients ) {
                print clients[val] > "clients.list";
            }
        }'  > "$fileout"

Після цього gnuplot’ом малюватимемо кожен набір даних окремим кольором, «іншими хрестиками», усереднюватимемо незалежно від решти тощо. Так, для цього треба трохи модифікувати «скрипт для gnuplot’а», але ж ми це справді можемо :-)

Чи буде це ілюстративніше?-) Напевно, буде! Але я не пробував .)

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.