add log viewer features and set log level functionality in admin panel

add "Get Logs for a new Release", which will create preformatted markdown text you can paste directly to the issue
This commit is contained in:
Kamil
2024-12-10 11:44:01 +00:00
parent 798c4ae28d
commit 7676189625
5 changed files with 231 additions and 4 deletions

View File

@@ -0,0 +1,162 @@
{% extends "admin.html" %}
{% block admin_content %}
{% if not logs %}
{% set logs = "Logfile empty or not found" %}
{% endif %}
{% set log_level = config['LOG_LEVEL'] %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.21.2/min/vs/loader.js"></script>
<div class="container-fluid mt-5">
<h1>Log Viewer</h1>
<div class="mb-3 row">
<form action="/admin/setloglevel" method="post" class="d-inline">
<label for="logLevel" class="form-label">Log Level</label>
<select class="form-select" id="logLevel" name="logLevel" required aria-describedby="loglevelHelp">
<option value="DEBUG" {% if log_level=="DEBUG" %}selected{% endif %}>DEBUG</option>
<option value="INFO" {% if log_level=="INFO" %}selected{% endif %}>INFO</option>
<option value="WARNING" {% if log_level=="WARNING" %}selected{% endif %}>WARNING</option>
<option value="ERROR" {% if log_level=="ERROR" %}selected{% endif %}>ERROR</option>
<option value="CRITICAL" {% if log_level=="CRITICAL" %}selected{% endif %}>CRITICAL</option>
</select>
<div id="loglevelHelp" class="form-text">Set the log level on demand.</div>
<button type="submit" class="btn btn-primary mt-2">Set Log Level</button>
</form>
</div>
<div class="mb-5 mt-3 row">
<button type="button" class="btn btn-warning" onclick="openCreateIssueModal()">Get Logs for a new Issue</button>
<!-- Modal HTML -->
<div class="modal fade" id="createIssueModal" tabindex="-1" aria-labelledby="createIssueModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="createIssueModalLabel">Create Issue</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<span class="m-2">Hit the copy button or copy this text manually and paste it to your GitHub
Issue.</span>
<div id="issue-text" style="height: 400px;"></div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" id="copyText" class="btn btn-primary">Copy</button>
</div>
<script>
async function setClipboard(text) {
const type = "text/plain";
const blob = new Blob([text], { type });
const data = [new ClipboardItem({ [type]: blob })];
await navigator.clipboard.write(data);
}
document.getElementById('copyText').addEventListener('click', function () {
const issueEditor = monaco.editor.getModels()[1];
const issueText = issueEditor.getValue();
if(!window.isSecureContext){
alert('Clipboard API is not available in insecure context. Please use a secure context (HTTPS) or just copy the text manually.');
return;
}
setClipboard(issueText);
});
</script>
</div>
</div>
</div>
</div>
<div class="mb-5 mt-3 row">
<label for="logType" class="form-label">Select Logs</label>
<select class="form-select" id="logType" name="logType" required
onchange="location.href='/admin/logs?name=' + this.value;">
<option value="logs" {% if name=="logs" %}selected{% endif %}>Logs</option>
<option value="worker" {% if name=="worker" %}selected{% endif %}>Worker Logs</option>
<option value="beat" {% if name=="beat" %}selected{% endif %}>Beat Logs</option>
</select>
</div>
<div class="mt-3 row" id="editor" style="height: 700px;">
</div>
<script>
require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.52.0/min/vs' } });
require(['vs/editor/editor.main'], function () {
monaco.languages.register({ id: "jellyplistLog" });
// Register a tokens provider for the language
monaco.languages.setMonarchTokensProvider("jellyplistLog", {
tokenizer: {
root: [
[/ERROR -.*/, "custom-error"],
[/WARNING -/, "custom-notice"],
[/INFO -/, "custom-info"],
[/DEBUG -.*/, "custom-debug"],
[/^\[\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2},\d{3}\]/, "custom-date"],
[/\s.*[a-zA-Z0-9_]+\.[a-z]{2,4}(?=:)/, "custom-filename"],
[/\d+(?= -)/, "custom-lineno"]
],
},
});
monaco.editor.defineTheme("jellyplistLogTheme", {
base: "vs-dark",
inherit: true,
rules: [
{ token: "custom-info", foreground: "808080" },
{ token: "custom-error", foreground: "ff0000", fontStyle: "bold" },
{ token: "custom-notice", foreground: "FFA500" },
{ token: "custom-debug", foreground: "851ea5" },
{ token: "custom-date", foreground: "90cc6f" },
{ token: "custom-filename", foreground: "d9d04f", fontStyle: "italic" },
{ token: "custom-lineno", foreground: "d9d04f", fontStyle: "light" },
],
colors: {
"editor.foreground": "#ffffff",
},
});
let editor = monaco.editor.create(document.getElementById('editor'), {
value: `{{ logs }}`,
language: 'jellyplistLog',
readOnly: true,
minimap: { enabled: false },
theme: 'jellyplistLogTheme',
automaticLayout: true
});
editor.revealLine(editor.getModel().getLineCount())
});
function openCreateIssueModal() {
const modal = new bootstrap.Modal(document.getElementById('createIssueModal'));
fetch('/admin/logs/getLogsForIssue')
.then(response => response.json())
.then(data => {
const issueText = data.logs;
const issueTextInput = document.getElementById('issue-text');
// before creating the new editor, remove the old one
while (issueTextInput.firstChild) {
issueTextInput.removeChild(issueTextInput.firstChild);
}
const issueEditor = monaco.editor.create(issueTextInput, {
value: issueText.join(''),
language: 'markdown',
minimap: { enabled: false },
automaticLayout: true
});
modal.show();
})
.catch(error => console.error('Error fetching issue logs:', error));
}
</script>
</div>
{% endblock %}