<%inherit file="base.html"/> <%! from plexpy import helpers %> <%def name="headIncludes()"> <link rel="stylesheet" href="${http_root}css/dataTables.bootstrap.min.css"> <link rel="stylesheet" href="${http_root}css/tautulli-dataTables.css"> <style> td {word-break: break-all;} </style> </%def> <%def name="headerIncludes()"> </%def> <%def name="body()"> <div class='container-fluid'> <div class='table-card-header'> <div class="header-bar"> <span><i class="fa fa-list-alt"></i> Logs</span> </div> <div class="button-bar"> <div class="btn-group" id="tautulli-log-levels"> <label> <select name="tautulli-log-level-filter" id="tautulli-log-level-filter" class="btn" style="color: inherit;"> <option value="">All log levels</option> <option disabled>────────────</option> <option value="DEBUG">Debug</option> <option value="INFO">Info</option> <option value="WARNING">Warning</option> <option value="ERROR">Error</option> </select> </label> </div> % if plex_log_files: <div class="btn-group" id="plex-log-files" style="display: none;"> <label> <select name="plex-log-files-filter" id="plex-log-files-filter" class="btn" style="color: inherit;"> <option value="">Select Plex Media Server log file</option> <option disabled>────────────</option> % for file in plex_log_files: <option value="${file}">${file}</option> % endfor </select> </label> </div> % endif <div class="btn-group" id="plex-log-levels" style="display: none;"> <label> <select name="plex-log-level-filter" id="plex-log-level-filter" class="btn" style="color: inherit;"> <option value="">All log levels</option> <option disabled>────────────</option> <option value="DEBUG">Debug</option> <option value="INFO">Info</option> <option value="WARN">Warning</option> <option value="ERROR">Error</option> </select> </label> </div> <button class="btn btn-dark" id="download-tautullilog"><i class="fa fa-download"></i> Download logs</button> <button class="btn btn-dark" id="download-plexserverlog" style="display: none;"><i class="fa fa-download"></i> Download logs</button> <button class="btn btn-dark" id="clear-notify-logs" style="display: none;"><i class="fa fa-trash-o"></i> Clear logs</button> <button class="btn btn-dark" id="clear-newsletter-logs" style="display: none;"><i class="fa fa-trash-o"></i> Clear logs</button> <button class="btn btn-dark" id="clear-login-logs" style="display: none;"><i class="fa fa-trash-o"></i> Clear logs</button> </div> </div> <div class='table-card-back'> <div> <ul id="log_tabs" class="nav nav-pills" role="tablist"> <li role="presentation" class="active"><a id="tautulli-logs-btn" href="#tabs-tautulli_log" aria-controls="tabs-tautulli_log" role="tab" data-toggle="tab">Tautulli Logs</a></li> <li role="presentation"><a id="tautulli-api-logs-btn" href="#tabs-tautulli_api_log" aria-controls="tabs-tautulli_api_log" role="tab" data-toggle="tab">Tautulli API Logs</a></li> <li role="presentation"><a id="plex-logs-btn" href="#tabs-plex_log" aria-controls="tabs-plex_log" role="tab" data-toggle="tab">Plex Media Server Logs</a></li> <li role="presentation"><a id="plex-websocket-logs-btn" href="#tabs-plex_websocket_log" aria-controls="tabs-plex_websocket_log" role="tab" data-toggle="tab">Plex Websocket Logs</a></li> <li role="presentation"><a id="notification-logs-btn" href="#tabs-notification_log" aria-controls="tabs-notification_log" role="tab" data-toggle="tab">Notification Logs</a></li> <li role="presentation"><a id="newsletter-logs-btn" href="#tabs-newsletter_log" aria-controls="tabs-newsletter_log" role="tab" data-toggle="tab">Newsletter Logs</a></li> <li role="presentation"><a id="login-logs-btn" href="#tabs-login_log" aria-controls="tabs-login_log" role="tab" data-toggle="tab">Login Logs</a></li> </ul> <div class="tab-content"> <div role="tabpanel" class="tab-pane active" id="tabs-tautulli_log" data-logfile="tautulli"> <table class="display" id="tautulli_log_table" width="100%"> <thead> <tr> <th class="min-tablet" align="left" id="timestamp">Timestamp</th> <th class="desktop" align="left" id="level">Level</th> <th class="all" align="left" id="message">Message</th> </tr> </thead> <tbody></tbody> </table> </div> <div role="tabpanel" class="tab-pane" id="tabs-tautulli_api_log" data-logfile="tautulli_api"> <table class="display" id="tautulli_api_log_table" width="100%"> <thead> <tr> <th class="min-tablet" align="left" id="timestamp">Timestamp</th> <th class="desktop" align="left" id="level">Level</th> <th class="all" align="left" id="message">Message</th> </tr> </thead> <tbody></tbody> </table> </div> <div role="tabpanel" class="tab-pane" id="tabs-plex_websocket_log" data-logfile="plex_websocket"> <table class="display" id="plex_websocket_log_table" width="100%"> <thead> <tr> <th class="min-tablet" align="left" id="timestamp">Timestamp</th> <th class="desktop" align="left" id="level">Level</th> <th class="all" align="left" id="message">Message</th> </tr> </thead> <tbody></tbody> </table> </div> <div role="tabpanel" class="tab-pane" id="tabs-plex_log"> <table class="display" id="plex_log_table" width="100%"> <thead> <tr> <th align="left" id="plex_timestamp">Timestamp</th> <th align="left" id="plex_level">Level</th> <th align="left" id="plex_message">Message</th> </tr> </thead> <tbody></tbody> </table> </div> <div role="tabpanel" class="tab-pane" id="tabs-notification_log"> <table class="display" id="notification_log_table" width="100%"> <thead> <tr> <th align="left" id="notification_timestamp">Timestamp</th> <th align="left" id="notification_notifier_id">Notifier ID</th> <th align="left" id="notification_agent_name">Agent</th> <th align="left" id="notification_notify_action">Action</th> <th align="left" id="notification_subject_text">Subject Text</th> <th align="left" id="notification_body_text">Body Text</th> <th align="left" id="notification_success"></th> </tr> </thead> <tbody></tbody> </table> </div> <div role="tabpanel" class="tab-pane" id="tabs-newsletter_log"> <table class="display" id="newsletter_log_table" width="100%"> <thead> <tr> <th align="left" id="newsletter_timestamp">Timestamp</th> <th align="left" id="newsletter_newsletter_id">Newsletter ID</th> <th align="left" id="newsletter_agent_name">Agent</th> <th align="left" id="newsletter_notify_action">Action</th> <th align="left" id="newsletter_subject_text">Subject Text</th> <th align="left" id="newsletter_body_text">Body Text</th> <th align="left" id="newsletter_start_date">Start Date</th> <th align="left" id="newsletter_end_date">End Date</th> <th align="left" id="newsletter_uuid">UUID</th> <th align="left" id="newsletter_success"></th> </tr> </thead> <tbody></tbody> </table> </div> <div role="tabpanel" class="tab-pane" id="tabs-login_log"> <table class="display login_log_table" id="login_log_table" width="100%"> <thead> <tr> <th align="left" id="login_timestamp">Timestamp</th> <th align="left" id="login_friendly_name">User</th> <th align="left" id="login_user_group">User Group</th> <th align="left" id="login_ip_address">IP Address</th> <th align="left" id="login_host">Host</th> <th align="left" id="login_os">Operating System</th> <th align="left" id="login_browser">Browser</th> <th align="left" id="login_expiry">Expiry</th> <th align="left" id="login_success"></th> </tr> </thead> <tbody></tbody> </table> </div> </div> </div> </div> </div> <br> <div align="center"> Refresh rate: <select id="refreshrate" onchange="setRefresh()"> <option value="0" selected="selected">No Refresh</option> <option value="5">5 Seconds</option> <option value="15">15 Seconds</option> <option value="30">30 Seconds</option> <option value="60">60 Seconds</option> <option value="300">5 Minutes</option> <option value="600">10 Minutes</option> </select> </div> </%def> <%def name="modalIncludes()"> <div class="modal fade" id="ip-info-modal" tabindex="-1" role="dialog" aria-labelledby="ip-info-modal"> </div> </%def> <%def name="javascriptIncludes()"> <script src="${http_root}js/jquery.dataTables.min.js"></script> <script src="${http_root}js/dataTables.bootstrap.min.js"></script> <script src="${http_root}js/dataTables.bootstrap.pagination.js"></script> <script src="${http_root}js/tables/logs.js${cache_param}"></script> <script src="${http_root}js/tables/plex_logs.js${cache_param}"></script> <script src="${http_root}js/tables/notification_logs.js${cache_param}"></script> <script src="${http_root}js/tables/newsletter_logs.js${cache_param}"></script> <script src="${http_root}js/tables/login_logs.js${cache_param}"></script> <script> $(document).ready(function() { loadtautullilogs('tautulli', selected_log_level); clearSearchButton('tautulli_log_table', log_table); }); var log_levels = ['DEBUG', 'INFO', 'WARN', 'ERROR']; function bindLogLevelFilter() { clearLogLevelFilter(); var log_level_column = this.api().column(1); var select = $('#plex-log-level-filter'); select.on('change', function () { var val = $.fn.dataTable.util.escapeRegex( $(this).val() ); var search_string = ''; var levelIndex = log_levels.indexOf(val); if (levelIndex >= 0) { search_string = '^' + log_levels .slice(levelIndex) .join('|') + '$'; } log_level_column .search(search_string, true, false) .draw(); }).change(); } function clearLogLevelFilter() { $('#plex-log-level-filter').off('change'); } var selected_log_level = null; function loadtautullilogs(logfile, selected_log_level) { log_table_options.ajax = { url: 'get_log', type: 'POST', data: function (d) { return { logfile: logfile, json_data: JSON.stringify(d), log_level: selected_log_level }; } }; log_table = $('#' + logfile + '_log_table').DataTable(log_table_options); $('#tautulli-log-level-filter').on('change', function () { selected_log_level = $(this).val() || null; log_table.draw(); }); } function loadPlexLogs(logfile) { plex_log_table_options.ajax = { url: 'get_plex_log', type: 'POST', data: { logfile: logfile } }; plex_log_table_options.initComplete = bindLogLevelFilter; plex_log_table = $('#plex_log_table').DataTable(plex_log_table_options); } function loadNotificationLogs() { notification_log_table_options.ajax = { url: 'get_notification_log', type: 'POST', data: function (d) { return { json_data: JSON.stringify(d) }; } }; notification_log_table = $('#notification_log_table').DataTable(notification_log_table_options); } function loadNewsletterLogs() { newsletter_log_table_options.ajax = { url: "get_newsletter_log", data: function (d) { return { json_data: JSON.stringify(d) }; } }; newsletter_log_table = $('#newsletter_log_table').DataTable(newsletter_log_table_options); } function loadLoginLogs() { login_log_table_options.pageLength = 50; login_log_table_options.ajax = { url: 'get_user_logins', type: 'POST', data: function (d) { return { json_data: JSON.stringify(d) }; } }; login_log_table = $('#login_log_table').DataTable(login_log_table_options); } $("#tautulli-logs-btn").click(function () { $("#tautulli-log-levels").show(); $("#plex-log-files").hide(); $("#plex-log-levels").hide(); $("#clear-logs").show(); $("#download-tautullilog").show(); $("#download-plexserverlog").hide(); $("#clear-notify-logs").hide(); $("#clear-newsletter-logs").hide(); $("#clear-login-logs").hide(); loadtautullilogs('tautulli', selected_log_level); clearSearchButton('tautulli_log_table', log_table); }); $("#tautulli-api-logs-btn").click(function () { $("#tautulli-log-levels").show(); $("#plex-log-files").hide(); $("#plex-log-levels").hide(); $("#clear-logs").show(); $("#download-tautullilog").show(); $("#download-plexserverlog").hide(); $("#clear-notify-logs").hide(); $("#clear-newsletter-logs").hide(); $("#clear-login-logs").hide(); loadtautullilogs('tautulli_api', selected_log_level); clearSearchButton('tautulli_api_log_table', log_table); }); $("#plex-websocket-logs-btn").click(function () { $("#tautulli-log-levels").show(); $("#plex-log-files").hide(); $("#plex-log-levels").hide(); $("#clear-logs").show(); $("#download-tautullilog").show(); $("#download-plexserverlog").hide(); $("#clear-notify-logs").hide(); $("#clear-newsletter-logs").hide(); $("#clear-login-logs").hide(); loadtautullilogs('plex_websocket', selected_log_level); clearSearchButton('plex_websocket_log_table', log_table); }); $("#plex-logs-btn").click(function () { $("#tautulli-log-levels").hide(); $("#plex-log-files").show(); $("#plex-log-levels").show(); $("#clear-logs").hide(); $("#download-tautullilog").hide(); $("#download-plexserverlog").show(); $("#clear-notify-logs").hide(); $("#clear-newsletter-logs").hide(); $("#clear-login-logs").hide(); loadPlexLogs(); clearSearchButton('plex_log_table', plex_log_table); }); $("#notification-logs-btn").click(function () { $("#tautulli-log-levels").hide(); $("#plex-log-files").hide(); $("#plex-log-levels").hide(); $("#clear-logs").hide(); $("#download-tautullilog").hide(); $("#download-plexserverlog").hide(); $("#clear-notify-logs").show(); $("#clear-newsletter-logs").hide(); $("#clear-login-logs").hide(); loadNotificationLogs(); clearSearchButton('notification_log_table', notification_log_table); }); $("#newsletter-logs-btn").click(function () { $("#tautulli-log-levels").hide(); $("#plex-log-files").hide(); $("#plex-log-levels").hide(); $("#clear-logs").hide(); $("#download-tautullilog").hide(); $("#download-plexserverlog").hide(); $("#clear-notify-logs").hide(); $("#clear-newsletter-logs").show(); $("#clear-login-logs").hide(); loadNewsletterLogs(); clearSearchButton('newsletter_log_table', newsletter_log_table); }); $("#login-logs-btn").click(function () { $("#tautulli-log-levels").hide(); $("#plex-log-files").hide(); $("#plex-log-levels").hide(); $("#clear-logs").hide(); $("#download-tautullilog").hide(); $("#download-plexserverlog").hide(); $("#clear-notify-logs").hide(); $("#clear-newsletter-logs").hide(); $("#clear-login-logs").show(); loadLoginLogs(); clearSearchButton('login_log_table', notification_log_table); }); $("#plex-log-files").on('change', function () { var logfile = $("option:selected", this).val(); loadPlexLogs(logfile); clearSearchButton('plex_log_table', plex_log_table); }); $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { $.fn.dataTable.tables({ visible: true, api: true }).columns.adjust(); }); $("#clear-logs").click(function () { var logfile = $(".tab-pane.active").data('logfile'); var title = $("#log_tabs li.active a").text(); $("#confirm-message").text("Are you sure you want to clear the " + title + "?"); $('#confirm-modal').modal(); $('#confirm-modal').one('click', '#confirm-button', function () { $.ajax({ url: 'delete_logs', type: 'POST', data: { logfile: logfile }, complete: function (xhr, status) { result = $.parseJSON(xhr.responseText); msg = result.message; if (result.result === 'success') { showMsg('<i class="fa fa-check"></i> ' + msg, false, true, 5000) } else { showMsg('<i class="fa fa-times"></i> ' + msg, false, true, 5000, true) } log_table.draw(); } }); }); }); $("#download-tautullilog").click(function () { var logfile = $(".tab-pane.active").data('logfile'); window.location.href = "download_log?logfile=" + window.encodeURIComponent(logfile); }); $("#download-plexserverlog").click(function () { var logfile = $("option:selected", "#plex-log-files").val(); window.location.href = "download_plex_log?logfile=" + window.encodeURIComponent(logfile); }); $("#clear-notify-logs").click(function () { $("#confirm-message").text("Are you sure you want to clear the Tautulli Notification Logs?"); $('#confirm-modal').modal(); $('#confirm-modal').one('click', '#confirm-button', function () { $.ajax({ url: 'delete_notification_log', type: 'POST', complete: function (xhr, status) { result = $.parseJSON(xhr.responseText); msg = result.message; if (result.result === 'success') { showMsg('<i class="fa fa-check"></i> ' + msg, false, true, 5000) } else { showMsg('<i class="fa fa-times"></i> ' + msg, false, true, 5000, true) } notification_log_table.draw(); } }); }); }); $("#clear-newsletter-logs").click(function () { $("#confirm-message").text("Are you sure you want to clear the Tautulli Newsletter Logs?"); $('#confirm-modal').modal(); $('#confirm-modal').one('click', '#confirm-button', function () { $.ajax({ url: 'delete_newsletter_log', type: 'POST', complete: function (xhr, status) { result = $.parseJSON(xhr.responseText); msg = result.message; if (result.result === 'success') { showMsg('<i class="fa fa-check"></i> ' + msg, false, true, 5000) } else { showMsg('<i class="fa fa-times"></i> ' + msg, false, true, 5000, true) } newsletter_log_table.draw(); } }); }); }); $("#clear-login-logs").click(function () { $("#confirm-message").text("Are you sure you want to clear the Tautulli Login Logs?"); $('#confirm-modal').modal(); $('#confirm-modal').one('click', '#confirm-button', function () { $.ajax({ url: 'delete_login_log', type: 'POST', complete: function (xhr, status) { result = $.parseJSON(xhr.responseText); msg = result.message; if (result.result === 'success') { showMsg('<i class="fa fa-check"></i> ' + msg, false, true, 5000) } else { showMsg('<i class="fa fa-times"></i> ' + msg, false, true, 5000, true) } window.location = 'auth/logout'; } }); }); }); var timer; function setRefresh() { refreshrate = document.getElementById('refreshrate'); if(refreshrate != null) { if(timer) { clearInterval(timer); } if(refreshrate.value !== 0) { timer = setInterval(function() { if ($("#tabs-tautulli_log").hasClass("active") || $("#tabs-tautulli_api_log").hasClass("active") || $("#tabs-plex_websocket_log").hasClass("active")) { log_table.ajax.reload(); } else if ($("#tabs-plex_log").hasClass("active")) { plex_log_table.ajax.reload(); } else if ($("#tabs-notificaiton_log").hasClass("active")) { notification_log_table.ajax.reload(); } else if ($("#tabs-login_log").hasClass("active")) { login_log_table.ajax.reload(); } }, 1000*refreshrate.value); } } } </script> </%def>