Skip to content

Commit

Permalink
add TopErrors widget based on error_rate (librenms#12926)
Browse files Browse the repository at this point in the history
style

style
  • Loading branch information
PipoCanaja authored May 31, 2021
1 parent 3a0c164 commit 2e8c336
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 0 deletions.
18 changes: 18 additions & 0 deletions LibreNMS/Util/Url.php
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,24 @@ public static function portThumbnail($port)
return self::portImage($graph_array);
}

/**
* @param Port $port
* @return string
*/
public static function portErrorsThumbnail($port)
{
$graph_array = [
'port_id' => $port->port_id,
'graph_type' => 'port_errors',
'from' => Carbon::now()->subDay()->timestamp,
'to' => Carbon::now()->timestamp,
'width' => 150,
'height' => 21,
];

return self::portImage($graph_array);
}

public static function portImage($args)
{
if (empty($args['bg'])) {
Expand Down
90 changes: 90 additions & 0 deletions app/Http/Controllers/Widgets/TopErrorsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php
/**
* TopErrorsController.php
*
* -Description-
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* @link https://www.librenms.org
* @copyright 2018 Tony Murray
* @copyright 2021 PipoCanaja
* @author Tony Murray <[email protected]>
* @author PipoCanaja
*/

namespace App\Http\Controllers\Widgets;

use App\Models\Port;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\View\View;

class TopErrorsController extends WidgetController
{
protected $title = 'Top Errors';
protected $defaults = [
'interface_count' => 5,
'time_interval' => 15,
'interface_filter' => null,
'device_group' => null,
'port_group' => null,
];

/**
* @param Request $request
* @return View
*/
public function getView(Request $request)
{
$data = $this->getSettings();

$query = Port::hasAccess($request->user())->with(['device' => function ($query) {
$query->select('device_id', 'hostname', 'sysName', 'status', 'os');
}])
->isValid()
->select('port_id', 'device_id', 'ifName', 'ifDescr', 'ifAlias')
->groupBy('port_id', 'device_id', 'ifName', 'ifDescr', 'ifAlias')
->where('poll_time', '>', Carbon::now()->subMinutes($data['time_interval'])->timestamp)
->where(function ($query) {
return $query
->where('ifInErrors_rate', '>', 0)
->orwhere('ifOutErrors_rate', '>', 0);
})
->isUp()
->when($data['device_group'], function ($query) use ($data) {
$query->inDeviceGroup($data['device_group']);
}, function ($query) {
$query->has('device');
})
->when($data['port_group'], function ($query) use ($data) {
$query->inPortGroup($data['port_group']);
})
->orderByRaw('SUM(LEAST(ifInErrors_rate, 9223372036854775807) + LEAST(ifOutErrors_rate, 9223372036854775807)) DESC')
->limit($data['interface_count']);

if ($data['interface_filter']) {
$query->where('ifType', '=', $data['interface_filter']);
}

$data['ports'] = $query->get();

return view('widgets.top-errors', $data);
}

public function getSettingsView(Request $request)
{
return view('widgets.settings.top-errors', $this->getSettings(true));
}
}
5 changes: 5 additions & 0 deletions database/seeders/DefaultWidgetSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ public function run()
'widget' => 'alertlog',
'base_dimensions' => '6,3',
],
[
'widget_title' => 'Top Errors',
'widget' => 'top-errors',
'base_dimensions' => '6,3',
],
];

$existing = DB::table('widgets')->pluck('widget');
Expand Down
45 changes: 45 additions & 0 deletions resources/views/widgets/settings/top-errors.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@extends('widgets.settings.base')

@section('form')
<div class="form-group">
<label for="interface_count-{{ $id }}" class="control-label">@lang('Number of interfaces'):</label>
<input class="form-control" type="number" min="1" step="1" name="interface_count" id="interface_count-{{ $id }}" value="{{ $interface_count }}">
</div>
<div class="form-group">
<label for="time_interval-{{ $id }}" class="control-label">@lang('Last polled (minutes)'):</label>
<input class="form-control" type="number" min="1" step="1" name="time_interval" id="time_interval-{{ $id }}" value="{{ $time_interval }}">
</div>
<div class="form-group">
<label for="interface_filter-{{ $id }}" class="control-label">@lang('Interface type'):</label>
<select class="form-control" id="interface_filter-{{ $id }}" name="interface_filter" data-placeholder="@lang('All Ports')">
@if($interface_filter)
<option value="{{ $interface_filter }}">{{ $interface_filter }}</option>
@endif
</select>
</div>
<div class="form-group">
<label for="device_group-{{ $id }}" class="control-label">@lang('Device group')</label>
<select class="form-control" name="device_group" id="device_group-{{ $id }}" data-placeholder="@lang('All Devices')">
@if($device_group)
<option value="{{ $device_group->id }}" selected>{{ $device_group->name }}</option>
@endif
</select>
</div>
<div class="form-group">
<label for="port_group-{{ $id }}" class="control-label">@lang('Port group')</label>
<select class="form-control" name="port_group" id="port_group-{{ $id }}" data-placeholder="@lang('All Ports')">
@if($port_group)
<option value="{{ $port_group->id }}" selected>{{ $port_group->name }}</option>
@endif
</select>
</div>

@endsection

@section('javascript')
<script type="text/javascript">
init_select2('#interface_filter-{{ $id }}', 'port-field', {limit: 100, field: 'ifType'}, '{{ $interface_filter ?: '' }}');
init_select2('#device_group-{{ $id }}', 'device-group', {});
init_select2('#port_group-{{ $id }}', 'port-group', {});
</script>
@endsection
21 changes: 21 additions & 0 deletions resources/views/widgets/top-errors.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<h4>Top {{ $interface_count }} errored interfaces polled within {{ $time_interval }} minutes</h4>
<div class="table-responsive">
<table class="table table-hover table-condensed table-striped bootgrid-table">
<thead>
<tr>
<th class="text-left">@lang('Device')</th>
<th class="text-left">@lang('Interface')</th>
<th class="text-left">@lang('Error Rate')</th>
</tr>
</thead>
<tbody>
@foreach($ports as $port)
<tr>
<td class="text-left">@deviceLink($port->device, $port->device->shortDisplayName())</td>
<td class="text-left">@portLink($port, $port->getShortLabel())</td>
<td class="text-left">@portLink($port, \LibreNMS\Util\Url::portErrorsThumbnail($port), 'port_errors')</td>
</tr>
@endforeach
</tbody>
</table>
</div>
1 change: 1 addition & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@
Route::post('syslog', 'SyslogController');
Route::post('top-devices', 'TopDevicesController');
Route::post('top-interfaces', 'TopInterfacesController');
Route::post('top-errors', 'TopErrorsController');
Route::post('worldmap', 'WorldMapController');
Route::post('alertlog-stats', 'AlertlogStatsController');
});
Expand Down

0 comments on commit 2e8c336

Please sign in to comment.