add Suricata monitoring (#13942)

* add poller

* add a generic alert graph

* add support for .total

* add the initial work on the suricata app page

* add applayer flow sources

* more rrd work and add more fields

* add a missing graph to the suricata page

* add suricata to the apps page

* all working now for suricata

* add some suricata alert examples

* all done with the php

* update the application docs for Suricata

* add another note about Suricata stats in the docs

* add the test file

* add the test JSON

* remove a unneeded newline from the appication docs

* correct the type uptime type

* packets graph should by packets/sec

* minor formatting cleanup

* one more minor formatting cleanup

* shot in the dark to see if something fixes the angry linter

* fix snmpsim file

* add metrics

* add values to the metrics

* add a missing comma to the json

* add a missing line to snmprec and cleanup json a bit

* a few more minor changes to see if this makes it happy... regened via scripts/json-app-tool.php

* see if this will make it happy

* add suricata to app discovery and hope that fixes it... take a shot in the dark as to why the linter errors strangely on two of the files

* fix json

* add a missing ] to the json

* rename two graphs so it does not trigger one alert and add a missing metric

* whoops, *_alertString is not a metric
This commit is contained in:
Zane C. Bowers-Hadley
2022-04-25 20:30:49 -05:00
committed by GitHub
parent f8d76b0571
commit cdf457fbc5
20 changed files with 2402 additions and 0 deletions
+27
View File
@@ -1324,6 +1324,33 @@ function get_sensor_label_color($sensor, $type = 'sensors')
return "<span class='label $label_style'>" . trim(Number::formatSi($sensor['sensor_current'], 2, 3, $unit)) . '</span>';
}
/**
* Returns a list of the various suricata instances for
* the specified device id.
*
* @param $device_id
* @return array
*/
function get_suricata_instances($device_id)
{
$options = [
'filter' => [
'type' => ['=', 'suricata'],
],
];
$component = new LibreNMS\Component();
$ourc = $component->getComponents($device_id, $options);
if (isset($ourc[$device_id])) {
$id = $component->getFirstComponentID($ourc, $device_id);
return json_decode($ourc[$device_id][$id]['instances']);
}
return [];
}
/**
* @params int unix time
* @params int seconds
@@ -0,0 +1,29 @@
<?php
$name = 'suricata';
$app_id = $app['app_id'];
$unit_text = 'status';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 0;
$transparency = 15;
if (isset($vars['instance'])) {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id'], $vars['instance']]);
} else {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id']]);
}
$rrd_list = [];
if (Rrd::checkRrdExists($rrd_filename)) {
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Alert Status',
'ds' => 'alert',
];
} else {
d_echo('RRD "' . $rrd_filename . '" not found');
}
require 'includes/html/graphs/generic_multi_line.inc.php';
@@ -0,0 +1,154 @@
<?php
$name = 'suricata';
$app_id = $app['app_id'];
$unit_text = 'flows/sec';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 0;
$transparency = 15;
if (isset($vars['instance'])) {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id'], $vars['instance']]);
} else {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id']]);
}
$rrd_list = [];
if (Rrd::checkRrdExists($rrd_filename)) {
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'DCERPC TCP',
'ds' => 'af_dcerpc_tcp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'DCERPC UDP',
'ds' => 'af_dcerpc_udp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'DHCP',
'ds' => 'af_dhcp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'DNS TCP',
'ds' => 'af_dns_tcp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'DNS UDP',
'ds' => 'af_dns_udp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Failed TCP',
'ds' => 'af_failed_tcp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Failed UDP',
'ds' => 'af_failed_udp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'FTP',
'ds' => 'af_ftp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'FTP-DATA',
'ds' => 'af_ftp_data',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'HTTP',
'ds' => 'af_http',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'IKEv2',
'ds' => 'af_ikev2',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'IMAP',
'ds' => 'af_imap',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Krb5 TCP',
'ds' => 'af_krb5_tcp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Krb5 UDP',
'ds' => 'af_krb5_udp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'MQTT',
'ds' => 'af_mqtt',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'NFS TCP',
'ds' => 'af_nfs_tcp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'NFS UDP',
'ds' => 'af_nfs_udp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'RDP',
'ds' => 'af_rdp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'RFB',
'ds' => 'af_rfb',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'SIP',
'ds' => 'af_sip',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'SMB',
'ds' => 'af_smb',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'SMTP',
'ds' => 'af_smtp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'SNMP',
'ds' => 'af_snmp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'ssh',
'ds' => 'af_ssh',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'TFTP',
'ds' => 'af_tftp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'TLS',
'ds' => 'af_tls',
];
} else {
d_echo('RRD "' . $rrd_filename . '" not found');
}
require 'includes/html/graphs/generic_multi_line.inc.php';
@@ -0,0 +1,144 @@
<?php
$name = 'suricata';
$app_id = $app['app_id'];
$unit_text = 'tx/sec';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 0;
$transparency = 15;
if (isset($vars['instance'])) {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id'], $vars['instance']]);
} else {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id']]);
}
$rrd_list = [];
if (Rrd::checkRrdExists($rrd_filename)) {
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'DCERPC TCP',
'ds' => 'at_dcerpc_tcp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'DCERPC UDP',
'ds' => 'at_dcerpc_udp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'DHCP',
'ds' => 'at_dhcp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'DNS TCP',
'ds' => 'at_dns_tcp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'DNS UDP',
'ds' => 'at_dns_udp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'FTP',
'ds' => 'at_ftp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'FTP-DATA',
'ds' => 'at_ftp_data',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'HTTP',
'ds' => 'at_http',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'IKEv2',
'ds' => 'at_ikev2',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'IMAP',
'ds' => 'at_imap',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Krb5 TCP',
'ds' => 'at_krb5_tcp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Krb5 UDP',
'ds' => 'at_krb5_udp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'MQTT',
'ds' => 'at_mqtt',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'NFS TCP',
'ds' => 'at_nfs_tcp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'NFS UDP',
'ds' => 'at_nfs_udp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'RDP',
'ds' => 'at_rdp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'RFB',
'ds' => 'at_rfb',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'SIP',
'ds' => 'at_sip',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'SMB',
'ds' => 'at_smb',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'SMTP',
'ds' => 'at_smtp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'SNMP',
'ds' => 'at_snmp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'ssh',
'ds' => 'at_ssh',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'TFTP',
'ds' => 'at_tftp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'TLS',
'ds' => 'at_tls',
];
} else {
d_echo('RRD "' . $rrd_filename . '" not found');
}
require 'includes/html/graphs/generic_multi_line.inc.php';
@@ -0,0 +1,29 @@
<?php
$name = 'suricata';
$app_id = $app['app_id'];
$unit_text = 'bytes/sec';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 0;
$transparency = 15;
if (isset($vars['instance'])) {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id'], $vars['instance']]);
} else {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id']]);
}
$rrd_list = [];
if (Rrd::checkRrdExists($rrd_filename)) {
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Bytes',
'ds' => 'bytes',
];
} else {
d_echo('RRD "' . $rrd_filename . '" not found');
}
require 'includes/html/graphs/generic_multi_line.inc.php';
@@ -0,0 +1,114 @@
<?php
$name = 'suricata';
$app_id = $app['app_id'];
$unit_text = 'packets/sec';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 0;
$transparency = 15;
if (isset($vars['instance'])) {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id'], $vars['instance']]);
} else {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id']]);
}
$rrd_list = [];
if (Rrd::checkRrdExists($rrd_filename)) {
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'IPv4',
'ds' => 'dec_ipv4',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'IPv6',
'ds' => 'dec_ipv6',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'TCP',
'ds' => 'dec_tcp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'UDP',
'ds' => 'dec_udp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'SCTP',
'ds' => 'dec_sctp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'CHDLC',
'ds' => 'dec_chdlc',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'GENEVE',
'ds' => 'dec_geneve',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'IEEE 802.1ah',
'ds' => 'dec_ieee8021ah',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'IPv4 in IPv6',
'ds' => 'dec_ipv4_in_ipv6',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'MPLS',
'ds' => 'dec_mpls',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'PPP',
'ds' => 'dec_ppp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'PPPoE',
'ds' => 'dec_pppoe',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'SLL',
'ds' => 'dec_sll',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Teredo',
'ds' => 'dec_teredo',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'VLAN',
'ds' => 'dec_vlan',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'VLAN Q-in-Q',
'ds' => 'dec_vlan_qinq',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'VNTAG',
'ds' => 'dec_vntag',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'VXLAN',
'ds' => 'dec_vxlan',
];
} else {
d_echo('RRD "' . $rrd_filename . '" not found');
}
require 'includes/html/graphs/generic_multi_line.inc.php';
@@ -0,0 +1,44 @@
<?php
$name = 'suricata';
$app_id = $app['app_id'];
$unit_text = 'flows';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 0;
$transparency = 15;
if (isset($vars['instance'])) {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id'], $vars['instance']]);
} else {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id']]);
}
$rrd_list = [];
if (Rrd::checkRrdExists($rrd_filename)) {
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'ICMPv4',
'ds' => 'f_icmpv4',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'ICMPv6',
'ds' => 'f_icmpv6',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'TCP',
'ds' => 'f_tcp',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'UDP',
'ds' => 'f_udp',
];
} else {
d_echo('RRD "' . $rrd_filename . '" not found');
}
require 'includes/html/graphs/generic_multi_line.inc.php';
@@ -0,0 +1,49 @@
<?php
$name = 'suricata';
$app_id = $app['app_id'];
$unit_text = 'bytes';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 0;
$transparency = 15;
if (isset($vars['instance'])) {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id'], $vars['instance']]);
} else {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id']]);
}
$rrd_list = [];
if (Rrd::checkRrdExists($rrd_filename)) {
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Flow',
'ds' => 'f_memuse',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'FTP',
'ds' => 'ftp_memuse',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'HTTP',
'ds' => 'http_memuse',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'TCP',
'ds' => 'tcp_memuse',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'TCP Reass',
'ds' => 'tcp_reass_memuse',
];
} else {
d_echo('RRD "' . $rrd_filename . '" not found');
}
require 'includes/html/graphs/generic_multi_line.inc.php';
@@ -0,0 +1,49 @@
<?php
$name = 'suricata';
$app_id = $app['app_id'];
$unit_text = 'packets/sec';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 0;
$transparency = 15;
if (isset($vars['instance'])) {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id'], $vars['instance']]);
} else {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id']]);
}
$rrd_list = [];
if (Rrd::checkRrdExists($rrd_filename)) {
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Dropped',
'ds' => 'dropped',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'IfDropped',
'ds' => 'ifdropped',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Errors',
'ds' => 'errors',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Dec_Invalid',
'ds' => 'dec_invalid',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Too_Many_Layers',
'ds' => 'dec_too_many_layer',
];
} else {
d_echo('RRD "' . $rrd_filename . '" not found');
}
require 'includes/html/graphs/generic_multi_line.inc.php';
@@ -0,0 +1,39 @@
<?php
$name = 'suricata';
$app_id = $app['app_id'];
$unit_text = 'Percent_Of_Packets';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 0;
$transparency = 15;
if (isset($vars['instance'])) {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id'], $vars['instance']]);
} else {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id']]);
}
$rrd_list = [];
if (Rrd::checkRrdExists($rrd_filename)) {
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Dropped',
'ds' => 'drop_percent',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'If_Dropped',
'ds' => 'ifdrop_percent',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Error',
'ds' => 'error_percent',
];
} else {
d_echo('RRD "' . $rrd_filename . '" not found');
}
require 'includes/html/graphs/generic_multi_line.inc.php';
@@ -0,0 +1,44 @@
<?php
$name = 'suricata';
$app_id = $app['app_id'];
$unit_text = 'packets/sec';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 1;
$addarea = 0;
$transparency = 15;
if (isset($vars['instance'])) {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id'], $vars['instance']]);
} else {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id']]);
}
$rrd_list = [];
if (Rrd::checkRrdExists($rrd_filename)) {
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Packets',
'ds' => 'packets',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Dec. Packets',
'ds' => 'dec_packets',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Dropped',
'ds' => 'dropped',
];
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'If Dropped',
'ds' => 'ifdropped',
];
} else {
d_echo('RRD "' . $rrd_filename . '" not found');
}
require 'includes/html/graphs/generic_multi_line.inc.php';
@@ -0,0 +1,29 @@
<?php
$name = 'suricata';
$app_id = $app['app_id'];
$unit_text = 'seconds';
$colours = 'psychedelic';
$dostack = 0;
$printtotal = 0;
$addarea = 0;
$transparency = 15;
if (isset($vars['instance'])) {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id'], $vars['instance']]);
} else {
$rrd_filename = Rrd::name($device['hostname'], ['app', $name, $app['app_id']]);
}
$rrd_list = [];
if (Rrd::checkRrdExists($rrd_filename)) {
$rrd_list[] = [
'filename' => $rrd_filename,
'descr' => 'Uptime',
'ds' => 'uptime',
];
} else {
d_echo('RRD "' . $rrd_filename . '" not found');
}
require 'includes/html/graphs/generic_multi_line.inc.php';
+12
View File
@@ -309,6 +309,18 @@ $graphs['freeradius'] = [
'proxy_acct',
'queue',
];
$graphs['suricata'] = [
'alert',
'packets',
'nasty_delta',
'nasty_percent',
'dec_proto',
'flow_proto',
'app_flows',
'app_tx',
'bytes',
'mem_use',
];
$graphs['zfs'] = [
'arc_misc',
'arc_size',
@@ -0,0 +1,73 @@
<?php
$suricata_instances = get_suricata_instances($device['device_id']);
$link_array = [
'page' => 'device',
'device' => $device['device_id'],
'tab' => 'apps',
'app' => 'suricata',
];
print_optionbar_start();
echo generate_link('Totals', $link_array);
echo '| Instances:';
$int_int = 0;
while (isset($suricata_instances[$int_int])) {
$instance = $suricata_instances[$int_int];
$label = $instance;
if ($vars['instance'] == $instance) {
$label = '<span class="pagemenu-selected">' . $instance . '</span>';
}
$int_int++;
$append = '';
if (isset($pools[$int_int])) {
$append = ', ';
}
echo generate_link($label, $link_array, ['pool'=>$pool]) . $append;
}
print_optionbar_end();
$graphs = [
'suricata_packets'=>'Packets',
'suricata_bytes'=>'Bytes',
'suricata_nasty_delta'=>'Drops or Errors Delta',
'suricata_nasty_percent'=>'Drops or Errors Percent',
'suricata_dec_proto'=>'Decoder Protocols',
'suricata_flow_proto'=>'Flow Protocols',
'suricata_app_flows'=>'App Layer Flows',
'suricata_app_tx'=>'App Layer TX',
'suricata_mem_use'=>'Memory Usage',
'suricata_uptime'=>'Uptime',
'suricata_alert'=>'Alert Status',
];
foreach ($graphs as $key => $text) {
$graph_type = $key;
$graph_array['height'] = '100';
$graph_array['width'] = '215';
$graph_array['to'] = \LibreNMS\Config::get('time.now');
$graph_array['id'] = $app['app_id'];
$graph_array['type'] = 'application_' . $key;
if (isset($vars['instance'])) {
$graph_array['instance'] = $vars['instance'];
}
echo '<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">' . $text . '</h3>
</div>
<div class="panel-body">
<div class="row">';
include 'includes/html/print-graphrow.inc.php';
echo '</div>';
echo '</div>';
echo '</div>';
}