Issues (2963)

app/Http/Controllers/Table/GraylogController.php (2 issues)

Labels
Severity
1
<?php
2
/**
3
 * GraylogController.php
4
 *
5
 * -Description-
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19
 *
20
 * @link       https://www.librenms.org
21
 *
22
 * @copyright  2018 Tony Murray
23
 * @author     Tony Murray <[email protected]>
24
 */
25
26
namespace App\Http\Controllers\Table;
27
28
use App\ApiClients\GraylogApi;
29
use App\Models\Device;
30
use DateInterval;
31
use DateTime;
32
use DateTimeZone;
33
use Illuminate\Http\Request;
34
use LibreNMS\Config;
35
use LibreNMS\Util\Url;
36
37
class GraylogController extends SimpleTableController
38
{
39
    private $timezone;
40
    private $deviceCache = [];
41
42
    public function __construct()
43
    {
44
        $timezone = Config::get('graylog.timezone');
45
        $this->timezone = $timezone ? new DateTimeZone($timezone) : null;
46
    }
47
48
    public function __invoke(Request $request, GraylogApi $api)
49
    {
50
        if (! $api->isConfigured()) {
51
            return response()->json([
52
                'error' => 'Graylog is not configured',
53
            ], 503);
54
        }
55
56
        $this->validate($request, [
57
            'stream' => 'nullable|alpha_num',
58
            'device' => 'nullable|int',
59
            'range' => 'nullable|int',
60
            'loglevel' => 'nullable|int|min:0|max:7',
61
        ]);
62
63
        $search = $request->get('searchPhrase');
64
        $device_id = $request->get('device');
65
        $device = $device_id ? Device::find($device_id) : null;
66
        $range = $request->get('range', 0);
67
        $limit = $request->get('rowCount', 10);
68
        $page = $request->get('current', 1);
69
        $offset = ($page - 1) * $limit;
70
        $loglevel = $request->get('loglevel') ?? Config::get('graylog.loglevel');
71
72
        $query = $api->buildSimpleQuery($search, $device) .
73
            ($loglevel !== null ? ' AND level: <=' . $loglevel : '');
74
75
        $sort = null;
76
        foreach ($request->get('sort', []) as $field => $direction) {
77
            $sort = "$field:$direction";
78
        }
79
80
        $stream = $request->get('stream');
81
        $filter = $stream ? "streams:$stream" : null;
82
83
        try {
84
            $data = $api->query($query, $range, $limit, $offset, $sort, $filter);
85
86
            return $this->formatResponse(
87
                array_map([$this, 'formatMessage'], $data['messages']),
88
                $page,
89
                count($data['messages']),
90
                $data['total_results']
91
            );
92
        } catch (\Exception $se) {
93
            $error = $se->getMessage();
94
        }
95
96
        return response()->json([
97
            'error' => $error,
98
        ], 500);
99
    }
100
101
    private function formatMessage($message)
102
    {
103
        if ($this->timezone) {
104
            $graylogTime = new DateTime($message['message']['timestamp']);
105
            $offset = $this->timezone->getOffset($graylogTime);
106
107
            $timeInterval = DateInterval::createFromDateString((string) $offset . 'seconds');
108
            $graylogTime->add($timeInterval);
109
            $displayTime = $graylogTime->format('Y-m-d H:i:s');
110
        } else {
111
            $displayTime = $message['message']['timestamp'];
112
        }
113
114
        $device = $this->deviceFromSource($message['message']['source']);
115
        $level = $message['message']['level'] ?? '';
116
        $facility = $message['message']['facility'] ?? '';
117
118
        return [
119
            'severity'  => $this->severityLabel($level),
120
            'timestamp' => $displayTime,
121
            'source'    => $device ? Url::deviceLink($device) : $message['message']['source'],
122
            'message'   => $message['message']['message'] ?? '',
123
            'facility'  => is_numeric($facility) ? "($facility) " . __("syslog.facility.$facility") : $facility,
0 ignored issues
show
Are you sure __('syslog.facility.'.$facility) of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

123
            'facility'  => is_numeric($facility) ? "($facility) " . /** @scrutinizer ignore-type */ __("syslog.facility.$facility") : $facility,
Loading history...
124
            'level'     => (is_numeric($level) && $level >= 0) ? "($level) " . __("syslog.severity.$level") : $level,
0 ignored issues
show
Are you sure __('syslog.severity.'.$level) of type array|string can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

124
            'level'     => (is_numeric($level) && $level >= 0) ? "($level) " . /** @scrutinizer ignore-type */ __("syslog.severity.$level") : $level,
Loading history...
125
        ];
126
    }
127
128
    private function severityLabel($severity)
129
    {
130
        $map = [
131
            '0' => 'label-danger',
132
            '1' => 'label-danger',
133
            '2' => 'label-danger',
134
            '3' => 'label-danger',
135
            '4' => 'label-warning',
136
            '5' => 'label-info',
137
            '6' => 'label-info',
138
            '7' => 'label-default',
139
            ''  => 'label-info',
140
        ];
141
        $barColor = isset($map[$severity]) ? $map[$severity] : 'label-info';
142
143
        return '<span class="alert-status ' . $barColor . '" style="margin-right:8px;float:left;"></span>';
144
    }
145
146
    /**
147
     * Cache device lookups so we don't lookup for every entry
148
     *
149
     * @param  mixed  $source
150
     * @return mixed
151
     */
152
    private function deviceFromSource($source)
153
    {
154
        if (! isset($this->deviceCache[$source])) {
155
            $this->deviceCache[$source] = Device::findByIp($source) ?: Device::findByHostname($source);
156
        }
157
158
        return $this->deviceCache[$source];
159
    }
160
}
161