Здравствуй, Хабр!
В процессе своей работы (администрирование активного оборудования) столкнулся с необходимостью оперативного получения онлайн-данных (желательно с графиком) входящего/исходящего трафика на сетевом интерфейсе по SNMP.
При этом всегда попадается такое оборудование, которое либо не заведено в систему мониторинга, либо требует просмотра статистики чаще, чем раз в минуту (как rrdtool).
А в арсенале, зачастую, лишь консоль сервера на Windows или Debian.
Вот тогда и появилась идея сделать небольшую утилитку обладающую следующими возможностями:
— кроссплатформенность;
— без зависимостей (статическая линковка библиотек);
— построение графиков в онлайн-режиме;
— построение графиков в консоли (псевдографика — спасибо, curses);
— шаблоны для специальных OID (пока один для ifInOctets и ifOutOctets);
— возможность прорисовки нескольких кастомных графиков.
Пока альфа-версия бинарников. Разместил здесь на Sourceforge.
Проверено на Windows 7/8/10 32-bit и 64-bit. Debian и Ubuntu.
Кушает данные SNMP — COUNTER, INTEGER, GAUGE.
Примеры запуска утилиты.
Список интерфейсов с OID.
wtraf 10.1.16.2 -l
Теперь знаем OID интерфейса (наш №3) и запускаем.
wtraf 10.1.16.2 -i 3
Результат на Windows 8 в небольшом консольном окне:
Результат на Ubuntu 18.04 LTS на весь экран:
Запускаем с интервалом сбора данных (раз в 5 сек.) и ограничиваем пропускную способность до 50 МБит/сек.
wtraf 10.1.16.2 -i 3 -n 5 -m 50
Результат в PuTTY (прим. — для удобства восприятия график исходящего трафика течет слева, входящего — справа):
А теперь самое сочное. Пример кастомных графиков.
wtraf.exe 10.1.16.2 -xc -a .1.3.6.1.2.1.2.2.1.10.2:LAN:rl:x,8,*,1000,/,1000,/:Mbit/s -a .1.3.6.1.2.1.2.2.1.10.3:Internet:bl:x,8,*,1000,/,1000,/:Mbit/s:80 -a .1.3.6.1.2.1.2.2.1.10.4:LAN_to_GUS:gl:x,8,*,1000,/,1000,/:Mbit/s
В свою очередь хочу довести до ума утилитку, может порадует админов.
Буду благодарен выявленным ошибкам. На данный момент их очень много, не все залатал.
Комментарии (27)
alex005
21.05.2018 11:31Утилита супер. Автору огромное спасибо! Для себя нашел применение делаешь tmux требуемую раскладку, сохраняешь. В мониторинге делаешь отдельный dashboard и через guacamole выводишь в iframe на этот дашбоард раскладку из tmux (можно сделать одной командой tmux attach) и получаешь графики в реальном времени в мониторинге, очень полезно для оперативной оценки ситуации.
timurnigamov
21.05.2018 11:57И еще не плохо бы видеть статус интерфейса up/down. И чтобы можно было отключать шапку таблицы. Т.е. вывод выглядел бы по маске: ||ifDescription|\n. Было бы совсем круто.
alex005
21.05.2018 12:16Ну да, это полезно для dashboard, всегда не хватает места. Подумайте пожалуйста, как можно компактно расположить требуемую информацию
Мои предложения такие не плохо кроме Description еще и видеть название интерфейса, т.е. например [gigabitethernet 1/0/1]:
>> Host: ..., Interface:… (up/down speed: 10 Gbit duplex full) Input Errors: и Output Errors: < — перенести в на две строки ниже и добавить скорость и дуплекс
+ interval: 5 sec, max limit: auto < — это вообще убрать
Outbound traffic: перенести в ту же строку где Max и Min
Сделать возможность выводить в текстовом виде следующие параметры одной командой
In_Avg_5: 171
Input Discards: 0/s
Input Errors: 0/s
Input bandwidth: 8.73 bit/s
Input non-unicast packets: 0/s
Input unicast packets: 0.02/s
Length of output queue: 0
Out_Avg_5: 875
Output Discards: 0/s
Output Errors: 0/s
Output bandwidth: 5.59 Kbit/s
Output non-unicast packets: 8.78/s
Output unicast packets: 0/s
так же не плохо было бы задавать маску для определения состояния, т.е. загружен на 90% например, Warning, и т.п.alex005
21.05.2018 12:25Пардон, название выводится. Добавлю еще, добавить возможность работать программе в фоновом режиме по заранее определенному файлу конфигурации, если будет маска по требуемому параметру вести (загрузка, ошибки и т.п.) лог, отображающий статус ОK -> WARNING Input bandwidth: 950 Mbit/c или WARNING -> OK.
shprnu Автор
21.05.2018 17:09Концепцию утилиты строил исходя из того, что входные параметры только по аргументам. Выводить информацию в лог, в принципе, можно реализовать.
timurnigamov
21.05.2018 12:28Да и еще обнаружил что ifDescription режется. В варианте без шапки снять ограничение на длину дескприпшена и убрать не значившийся пробелы. Была бы клевая утиля для нагиособразных утилит.
alex005
21.05.2018 12:38Как автору можно перевести donat за программу?
Да, можно было бы в мониторинг для некоторых интерфейсов отправлять информацию из нее в realtime, чего так не хватает. Например сохранять все опросы за 1 s в rrd файл и выводить их в спец графики.
shprnu Автор
21.05.2018 13:22Понял, рассмотрим. Если что напишу в личку.
alex005
21.05.2018 14:27Вот этим js можно было бы выводить график в realtime
github.com/terenn/rrdgraph-jsshprnu Автор
21.05.2018 15:41Главный цель программы, выводить графики в консоли без лишних телодвижений. В том числе установки дополнительного ПО и библиотек.
alex005
21.05.2018 16:22Это понятно, я просто написал, как я планирую выводить графики в realtime, если вы сделаете сохранение опросов в rrd/rra и лог файл.
timurnigamov
21.05.2018 15:49Мне идея утилиты понравилась. Но показалась, что она работает несколько медленно по крайней мере с опцией -l. Я тут пораскинул умишком и на коленках изобразил одну из возможностей Вашей утили на perl. Реализована опция только -l. Представляю на суд общественности свою версию. В моем случае Ваша утилита работает 18 секунд, а моя 4 секунды
#!/usr/bin/perl -w
#
use strict;
#
#OIDS
use Net::SNMP qw(:snmp);
use Data::Dumper qw(Dumper);
use vars qw($OURVAR);
#
#Debug mode
my $debug=0;
my $log_file="/usr/share/cacti/log/test_query_juniper_rsvp_pl.log";
my $log_open = 0;
my $verbose=1;
my $xml_delimiter=':';
#
my ($snmp_auth,$snmp_community,$snmp_version,$snmp_port,$timeout,$snmp_user,$snmp_pw);
my ($result,$session,$error);
my $retries=1;
#
#SNMP OIDS;
my $ifIndex =".1.3.6.1.2.1.2.2.1.1";
my $ifStatus = ".1.3.6.1.2.1.2.2.1.8";
my $ifDescription = ".1.3.6.1.2.1.2.2.1.2";
my $ifName = ".1.3.6.1.2.1.31.1.1.1.1";
my $ifAlias = ".1.3.6.1.2.1.31.1.1.1.18";
my $ifType = ".1.3.6.1.2.1.2.2.1.3";
my $ifSpeed = ".1.3.6.1.2.1.2.2.1.5";
my $ifHWaddress = ".1.3.6.1.2.1.2.2.1.6";
my $ifInOctets = ".1.3.6.1.2.1.2.2.1.10";
my $ifOutOctets = ".1.3.6.1.2.1.2.2.1.16";
my $ifOutOctets64 = ".1.3.6.1.2.1.31.1.1.1.10";
my $FcIdName = ".1.3.6.1.4.1.2636.3.15.3.1.2";
my $FabricPriority = ".1.3.6.1.4.1.2636.3.15.3.1.3";
#
sub usage()
{
print «Usage: wtraf.pl -cCommunity -v(1|2) -l ip_device\n»;
}
#
#Main
#
#
my ($command,$i,$option,$ip,$list,$short)=0;
$snmp_version=1;
$snmp_community=«public»;
$timeout=1;
if ($#ARGV == -1 ){usage();exit;}
else{$i=0;
foreach $option (@ARGV)
{
chomp ($option);
if (($option =~ m/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/) and ($i == $#ARGV)){$ip=$option;print «IPV4: $option\n»;}
elsif (($option =~ m/^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/) and ($i != $#ARGV)){
print «Wrong command line ip address must be last.\n»;
usage; exit;}
elsif ($option =~ m/\-l/){$command=$option;print «Option: $list\n»;$list=1;}
elsif ($option =~ m/^\-c\w+?$/) {
$snmp_community=$option;$snmp_community =~ s/^\-c//;
print«Community:$snmp_community\n»;}
elsif ($option =~ m/(^\-v\d$)/) {
$snmp_version=$option;
$snmp_version =~ s/^\-v//;
print«Version:$snmp_version\n»;}
$i++;
}
if ($command eq "-l"){print«List intrefaces:\n»}
print «Command line options:\nipv4:$ip\ncomunity:$snmp_community\nversion:$snmp_version\n»;
}
my %index_table;
if ($list==1){
($session,$error) = Net::SNMP->session(
-hostname => $ip,
-community => $snmp_community,
-version => $snmp_version,
-timeout => $timeout,
-retries=> 1,
-nonblocking => 0,
);
if ( !defined $session) { printf «ERROR: %s.\n», $error; exit 1}
####ifIndex
my $request_oid=$ifIndex;
$result = $session->get_table(
-baseoid => $request_oid,
-maxrepetitions => 10,
);
my %ifIndex=();
my %table=%{$result};
foreach my $key (keys %table)
{
my $data= $table{$key};
if ($key =~ /\.(\d+)$/)
{$key=$1;}
$ifIndex{$key}=$data;
}
####ifName
$request_oid=$ifName;
$result = $session->get_table(
-baseoid => $request_oid,
-maxrepetitions => 10,
);
if (!defined $result) { printf «ERROR: %s\n», $session->error(); $session->close(); exit 1; }
my %ifName=();
%table=%{$result};
foreach my $key (keys %table)
{
my $data= $table{$key};
if ($key =~ /\.(\d+)$/)
{$key=$1;}
$ifName{$key}=$data;
}
####ifAlias
$request_oid=$ifAlias;
$result = $session->get_table(
-baseoid => $request_oid,
-maxrepetitions => 10,
);
if (!defined $result) { printf «ERROR: %s\n», $session->error(); $session->close(); exit 1; }
my %ifAlias=();
%table=%{$result};
foreach my $key (keys %table)
{
my $data= $table{$key};
if ($key =~ /\.(\d+)$/)
{$key=$1;}
$ifAlias{$key}=$data;
}
####ifStatus
$request_oid=$ifStatus;
$result = $session->get_table(
-baseoid => $request_oid,
-maxrepetitions => 10,
);
if (!defined $result) { printf «ERROR: %s\n», $session->error(); $session->close(); exit 1; }
my %ifStatus=();
%table=%{$result};
foreach my $key (keys %table)
{
my $data= $table{$key};
if ($key =~ /\.(\d+)$/)
{$key=$1;}
$ifStatus{$key}=$data;
}
###############################
snmp_dispatcher();
$session->close();
my data="";
foreach my $key (sort keys %ifIndex)
{
print "$ifIndex{$key}|$ifName{$key}|$ifAlias{$key}|$ifStatus{$key}\n";
}
}
#Endshprnu Автор
21.05.2018 16:51Спасибо, как раз ранее был написан скрипт на perl.
Для автономности решено было собрать статические библиотеки net-snmp, pdcurses(ncurses) и boost. И написать утилитку на c++.
Ввиду сырости программы такая пока скорость, буду улучшать.
Для сбора информации по интерфейсам использую функцию библиотеки net-snmp:
«netsnmp_query_walk(hrprload_var, sess_handle);»
N0Good
22.05.2018 09:59Эх, ещё бы совместимость с arm…
shprnu Автор
22.05.2018 10:49Поподробней пожалуйста. Может реализуем.
N0Good
22.05.2018 11:33Имеется ввиду возможность сборки (или готовый бинарник) для архитектуры arm, armv7l и т.п.(всевозможные одноплатники). Вероятно, после переезда исходников на github проблем собрать самому не возникнет, но всё же…
chemtech
Спасибо за приложение! Планируется ли переезд на GitHub? (На GitHub легче отправлять pull request)
shprnu Автор
Да, планируется. Разместил на скорую руку. В том числе планируется выложить исходники.