Tor log implementation
This commit is contained in:
21
web/api/tor_log.php
Normal file
21
web/api/tor_log.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
require __DIR__ . '/../lib/app.php';
|
||||
auth_require();
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$n = isset($_GET['n']) ? (int)$_GET['n'] : 500;
|
||||
if ($n < 50) $n = 50;
|
||||
if ($n > 5000) $n = 5000;
|
||||
|
||||
$level = isset($_GET['level']) ? strtolower($_GET['level']) : 'info';
|
||||
$allowed = ['debug','info','notice','warning','err'];
|
||||
if (!in_array($level, $allowed, true)) $level = 'info';
|
||||
|
||||
$cmd = sprintf('sudo /usr/local/bin/torpanel-logdump %d %s', $n, escapeshellarg($level));
|
||||
exec($cmd . ' 2>&1', $out, $rc);
|
||||
|
||||
if ($rc === 0 && !empty($out)) {
|
||||
echo json_encode(['ok' => true, 'lines' => $out]);
|
||||
} else {
|
||||
echo json_encode(['ok' => false, 'error' => 'no_log', 'rc' => $rc]);
|
||||
}
|
||||
@@ -22,6 +22,8 @@ auth_require();
|
||||
Tor Relay Panel
|
||||
</span>
|
||||
<div class="ms-auto d-flex align-items-center gap-2">
|
||||
<!-- NEW: Tor Log button -->
|
||||
<button id="btnTorLog" class="btn btn-sm btn-outline-light">View Tor Log</button>
|
||||
<button id="btnTheme" class="btn btn-sm btn-outline-light">Theme</button>
|
||||
<a class="btn btn-sm btn-outline-light" href="/logout.php">Logout</a>
|
||||
</div>
|
||||
@@ -198,6 +200,32 @@ auth_require();
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="torlogModal" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,.6); z-index:1050;">
|
||||
<div style="background:#111; color:#eee; max-width:960px; height:70vh; margin:5vh auto; border-radius:12px; overflow:hidden; box-shadow:0 10px 30px rgba(0,0,0,.4); border:1px solid rgba(255,255,255,.08)">
|
||||
<div class="d-flex align-items-center justify-content-between p-2" style="background:#1b1b1b; border-bottom:1px solid rgba(255,255,255,.08)">
|
||||
<div class="fw-semibold">Tor Log</div>
|
||||
<div class="d-flex gap-2 align-items-center">
|
||||
<select id="torlogLevel" class="form-select form-select-sm bg-dark text-light" style="width:auto;">
|
||||
<option value="info" selected>info</option>
|
||||
<option value="notice">notice</option>
|
||||
<option value="warning">warning</option>
|
||||
<option value="err">err</option>
|
||||
<option value="debug">debug</option>
|
||||
</select>
|
||||
<select id="torlogLines" class="form-select form-select-sm bg-dark text-light" style="width:auto;">
|
||||
<option value="200">Last 200</option>
|
||||
<option value="500" selected>Last 500</option>
|
||||
<option value="1000">Last 1000</option>
|
||||
<option value="2000">Last 2000</option>
|
||||
</select>
|
||||
<button id="torlogRefresh" class="btn btn-sm btn-outline-light">Refresh</button>
|
||||
<button id="torlogClose" class="btn btn-sm btn-light text-dark">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
<pre id="torlogPre" class="p-3 m-0" style="background:#0c0c0c; color:#cdd3df; height:calc(70vh - 56px); overflow:auto; font-family:ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace; font-size:12px; line-height:1.35"></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const $ = (id) => document.getElementById(id);
|
||||
const el = {
|
||||
@@ -240,7 +268,6 @@ function applyTheme(theme){
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
localStorage.setItem(THEME_KEY, theme);
|
||||
setBtnLabel(theme);
|
||||
// Recolor chart axes/grid
|
||||
if (chart){
|
||||
const c = getThemeColors();
|
||||
chart.options.scales.x.ticks.color = c.text;
|
||||
@@ -442,6 +469,38 @@ if (el.cfgForm){
|
||||
setInterval(refreshChart, 60000);
|
||||
setInterval(loadReach, 60000);
|
||||
})();
|
||||
|
||||
(function(){
|
||||
const m = document.getElementById('torlogModal');
|
||||
const btn = document.getElementById('btnTorLog');
|
||||
const pre = document.getElementById('torlogPre');
|
||||
const lines= document.getElementById('torlogLines');
|
||||
const lvl = document.getElementById('torlogLevel');
|
||||
const close= document.getElementById('torlogClose');
|
||||
const ref = document.getElementById('torlogRefresh');
|
||||
|
||||
async function loadLog(){
|
||||
const n = lines?.value || '500';
|
||||
const L = lvl?.value || 'info';
|
||||
try{
|
||||
const res = await fetch('api/tor_log.php?n=' + encodeURIComponent(n) + '&level=' + encodeURIComponent(L), {cache:'no-store'});
|
||||
if (!res.ok){ pre.textContent = 'Failed to load log.'; return; }
|
||||
const json = await res.json();
|
||||
if (!json.ok){ pre.textContent = 'No logs available.'; return; }
|
||||
pre.textContent = (json.lines||[]).join('\n');
|
||||
pre.scrollTop = pre.scrollHeight;
|
||||
}catch(e){
|
||||
pre.textContent = 'Error: ' + e;
|
||||
}
|
||||
}
|
||||
|
||||
btn?.addEventListener('click', ()=>{ m.style.display='block'; loadLog(); });
|
||||
lines?.addEventListener('change', loadLog);
|
||||
lvl?.addEventListener('change', loadLog);
|
||||
document.getElementById('torlogRefresh')?.addEventListener('click', loadLog);
|
||||
document.getElementById('torlogClose')?.addEventListener('click', ()=>{ m.style.display='none'; });
|
||||
m?.addEventListener('click', (e)=>{ if (e.target === m) m.style.display='none'; });
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user