]> jfr.im git - irc/unrealircd/unrealircd-webpanel.git/commitdiff
Start on "Logs" (log viewer). This only shows live logs at the moment.
authorBram Matthys <redacted>
Thu, 27 Apr 2023 17:22:07 +0000 (19:22 +0200)
committerBram Matthys <redacted>
Thu, 27 Apr 2023 17:22:07 +0000 (19:22 +0200)
Still to do:
* Click = all details
* Fetch past XYZ log entries (requires new unrealircd api call)

Since 'responsive' datatables were not working, i made it non-responsive
and did the responsiveness myself based on resolutions etc.
I kinda hate the manual fiddling but now it works great on mobile both
in landscape and portrait mode, and on various desktop resolutions.

api/log.php [new file with mode: 0644]
inc/common.php
inc/header.php
js/unrealircd-admin.js
logs/index.php [new file with mode: 0644]

diff --git a/api/log.php b/api/log.php
new file mode 100644 (file)
index 0000000..ebc8fff
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+
+require_once('common_api.php');
+
+if (!$rpc)
+    die();
+
+/* Basically everything ;) */
+api_log_loop(["all", "!debug"]);
index 3dcfcc1c8a2bd636a3dcc2c25f90628868415087..fe3ec72652f704ce11bce637f7677187f8d4894f 100644 (file)
@@ -456,6 +456,7 @@ $pages = [
                "Ban Exceptions" => ["script" => "server-bans/ban-exceptions.php"],
        ],
        "Spamfilter"   => ["script" => "spamfilter.php"],
+       "Logs"   => ["script" => "logs/index.php"],
        "Tools" => [
                "IP WHOIS" => ["script" => "tools/ip-whois.php","no_irc_server_required"=>true],
        ],
index f153f0c438b3d73b399e9757a07cec27e04bae18..41670296701f894f95fe56fc8984ef206fedcaa3 100644 (file)
@@ -39,6 +39,7 @@ $arr = []; Hook::run(HOOKTYPE_PRE_HEADER, $arr);
 <script src="<?php echo get_config("base_url"); ?>js/datatables.min.js"></script>
 <script src="<?php echo get_config("base_url"); ?>js/datatables-natural-sort.js"></script>
 <script src="<?php echo get_config("base_url"); ?>js/datatables-ellipsis.js"></script>
+<script src="<?php echo get_config("base_url"); ?>js/moment-with-locales.min.js"></script>
 <script>
                var BASE_URL = "<?php echo get_config("base_url"); ?>";
                function timeoutCheck() {
index 4aa5fa1427968421120b733d512d18b706878ccb..5d28b9b3b326b5cd6c6ca3a2751882a01a4daaf3 100644 (file)
@@ -63,6 +63,8 @@ function toggle_checkbox(source) {
     }
 }
 
+/* Popup notifications */
+
 function generate_notif(title, body)
 {
     /* generate a random number between 1000 and 90000 to use as an id */
@@ -128,10 +130,37 @@ function StreamNotifs(e)
     msg = data.msg;
     generate_notif(title, msg);
 }
+
 function StartStreamNotifs(url)
 {
     if (!!window.EventSource) {
         var source = new EventSource(url);
         source.addEventListener('message', StreamNotifs, false);
     }
-}
\ No newline at end of file
+}
+
+/* Log streamer */
+function NewLogEntry(e)
+{
+    var data;
+    try {
+        data = JSON.parse(e.data);
+    } catch(e) {
+        return;
+    }
+    //$('#data_list_table').DataTable()
+    data_list_table.row.add({
+        'Time':data.timestamp,
+        'Level':data.level,
+        'Subsystem':data.subsystem,
+        'Event':data.event_id,
+        'Message':data.msg}).draw(true);
+    data_list_table.rows().invalidate();
+    data_list_table.searchPanes.rebuildPane();
+}
+
+function StartLogStream(url)
+{
+    var source = new EventSource(url);
+    source.addEventListener('message', NewLogEntry, false);
+}
diff --git a/logs/index.php b/logs/index.php
new file mode 100644 (file)
index 0000000..d0aeaba
--- /dev/null
@@ -0,0 +1,162 @@
+<?php
+require_once "../inc/common.php";
+require_once "../inc/header.php";
+?>
+<h4>Log viewer</h4>
+
+       <!-- The log table -->
+       <form method="post">
+       <table id="data_list" class="table-striped display nowrap" style="width:100%">
+       <thead>
+               <th scope="col">Time</th>
+               <th scope="col">Level</th>
+               <th scope="col">Subsystem</th>
+               <th scope="col">Event</th>
+               <th scope="col">Message</th>
+       </thead>
+       </table>
+       </form>
+
+<script>
+let data_list_table = null;
+
+function level2color(level)
+{
+       if (level == 'info')
+               return 'green';
+       if (level == 'warn')
+               return 'orange';
+       if ((level == 'error') || (level == 'fatal'))
+               return 'red';
+}
+
+function log_colorizer(data, type, row)
+{
+       if (type == 'display')
+       {
+               var color = level2color(row['Level']);
+               data = '<span style="color: '+color+'">' + data + '</span>';
+       }
+       return data;
+}
+
+function log_timestamp(data, type, row)
+{
+       if (type == 'display')
+       {
+               return moment.utc(data).local().format('HH:mm:ss');
+       }
+       return data;
+}
+
+function resize_check()
+{
+       if (window.innerWidth < 900)
+       {
+               data_list_table.column(1).visible(false); // level
+               data_list_table.column(2).visible(false); // subsystem
+               data_list_table.column(3).visible(false); // event
+       } else 
+       if (window.innerWidth < 1250)
+       {
+               data_list_table.column(1).visible(true);  // level
+               data_list_table.column(2).visible(false); // subsystem
+               data_list_table.column(3).visible(false); // event
+       } else 
+       if (window.innerWidth < 1450)
+       {
+               data_list_table.column(1).visible(true);  // level
+               data_list_table.column(2).visible(true);  // subsystem
+               data_list_table.column(3).visible(false); // event
+       } else
+       {
+               data_list_table.column(1).visible(true);  // level
+               data_list_table.column(2).visible(true);  // subsystem
+               data_list_table.column(3).visible(true); // event
+       }
+       data_list_table.rows().invalidate('data').draw(false);
+}
+
+function log_text(data, type, row)
+{
+       var esc = function (t) {
+           return ('' + t)
+               .replace(/&/g, '&amp;')
+               .replace(/</g, '&lt;')
+               .replace(/>/g, '&gt;')
+               .replace(/"/g, '&quot;');
+       };
+
+       if (type != 'display')
+               return data;
+
+       var color = level2color(row['Level']);
+       var cutoff;
+       if (window.innerWidth < 500)
+               cutoff = 35;
+       else if (window.innerWidth < 1000)
+               cutoff = 75;
+       else if (window.innerWidth < 1750)
+               cutoff = 100
+       else
+               cutoff = 125;
+
+       if (data.length > cutoff)
+       {
+               // stolen from ellipsis
+               var shortened = data.substr(0, cutoff - 1);
+               data = '<span class="ellipsis" style="color: '+color+'" title="' +
+                   esc(data) +
+                   '">' +
+                   shortened +
+                   '&#8230;</span>';
+       } else {
+               // otherwise just like log_colorizer...
+               data = '<span style="color: '+color+'">' + data + '</span>';
+       }
+       return data;
+}
+
+$(document).ready( function () {
+       args = {
+               //'responsive': true,
+               'fixedHeader': {
+                       header: true,
+                       headerOffset: 53
+               },
+               'columns': [
+                       { 'data': 'Time', 'responsivePriority': 1, 'render': log_timestamp },
+                       { 'data': 'Level', 'responsivePriority': 3, 'className':'virtuallink', 'render': log_colorizer },
+                       { 'data': 'Subsystem', 'responsivePriority': 4, 'render': log_colorizer },
+                       { 'data': 'Event', 'responsivePriority': 5, 'render': log_colorizer },
+                       //{ 'data': 'Message', 'responsivePriority': 2, 'render': DataTable.render.ellipsis(100, false) },
+                       { 'data': 'Message', 'responsivePriority': 2, 'render': log_text },
+               ],
+               'pageLength':100,
+               'order':[[0,'desc']],
+       };
+
+       /* Only show filter pane on desktop */
+       if (window.innerWidth > 8000)
+       {
+               args['dom'] = 'Pfrtip';
+               args['searchPanes'] = {
+                       'initCollapsed': 'true',
+                       'columns': [1,2,3],
+                       'dtOpts': {
+                               select: { style: 'multi'},
+                               order: [[ 1, "desc" ]]
+                       },
+               }
+       }
+
+       data_list_table = $('#data_list').DataTable(args);
+
+       resize_check();
+       window.addEventListener('resize', resize_check);
+
+       StartLogStream('<?php echo get_config('base_url'); ?>api/log.php');
+} );
+</script>
+
+<?php require_once '../inc/footer.php'; ?>