add container log view

This commit is contained in:
Raven Scott 2024-12-02 00:02:36 -05:00
parent 3e37359e61
commit 77122a58b7
3 changed files with 156 additions and 71 deletions

40
app.js
View File

@ -339,6 +339,13 @@ function handlePeerData(data, topicId, peer) {
}
break;
case 'logs':
console.log('[INFO] Handling logs output...');
if (window.handleLogOutput) {
window.handleLogOutput(response);
}
break;
default:
console.warn(`[WARN] Unhandled response type: ${response.type}`);
break;
@ -704,6 +711,9 @@ function renderContainers(containers, topicId) {
<button class="btn btn-warning btn-sm action-stop" ${container.State !== 'running' ? 'disabled' : ''}>
<i class="fas fa-stop"></i>
</button>
<button class="btn btn-dark btn-sm action-logs">
<i class="fas fa-binoculars"></i>
</button>
<button class="btn btn-danger btn-sm action-remove">
<i class="fas fa-trash"></i>
</button>
@ -713,6 +723,7 @@ function renderContainers(containers, topicId) {
<button class="btn btn-secondary btn-sm action-duplicate">
<i class="fas fa-clone"></i>
</button>
</td>
`;
containerList.appendChild(row);
@ -813,6 +824,35 @@ function addActionListeners(row, container) {
}
});
const logsBtn = row.querySelector('.action-logs');
logsBtn.addEventListener('click', () => openLogModal(container.Id));
function openLogModal(containerId) {
console.log(`[INFO] Opening logs modal for container: ${containerId}`);
const modal = new bootstrap.Modal(document.getElementById('logsModal'));
const logContainer = document.getElementById('logs-container');
// Clear any existing logs
logContainer.innerHTML = '';
// Request previous logs
sendCommand('logs', { id: containerId });
// Listen for logs
window.handleLogOutput = (logData) => {
const logLine = atob(logData.data); // Decode base64 logs
const logElement = document.createElement('pre');
logElement.textContent = logLine;
logContainer.appendChild(logElement);
// Scroll to the bottom
logContainer.scrollTop = logContainer.scrollHeight;
};
// Show the modal
modal.show();
}
// Remove Button
removeBtn.addEventListener('click', async () => {

View File

@ -531,6 +531,20 @@
</div>
</div>
<div class="modal fade" id="logsModal" tabindex="-1" aria-labelledby="logsModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content bg-dark text-white">
<div class="modal-header">
<h5 class="modal-title" id="logsModalLabel">Container Logs</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="logs-container" style="max-height: 70vh; overflow-y: auto; font-family: monospace; background: black; padding: 10px;"></div>
</div>
</div>
</div>
</div>
<!-- Alert Container -->
<div id="alert-container" class="position-fixed top-0 start-50 translate-middle-x mt-3"
style="z-index: 1051; max-width: 90%;"></div>

View File

@ -162,6 +162,37 @@ swarm.on('connection', (peer) => {
}
break;
case 'logs':
console.log(`[INFO] Handling 'logs' command for container: ${parsedData.args.id}`);
const logsContainer = docker.getContainer(parsedData.args.id);
const logsStream = await logsContainer.logs({
stdout: true,
stderr: true,
tail: 100, // Fetch the last 100 log lines
follow: true, // Stream live logs
});
logsStream.on('data', (chunk) => {
peer.write(
JSON.stringify({
type: 'logs',
data: chunk.toString('base64'), // Send base64 encoded logs
})
);
});
logsStream.on('end', () => {
console.log(`[INFO] Log stream ended for container: ${parsedData.args.id}`);
});
logsStream.on('error', (err) => {
console.error(`[ERROR] Log stream error for container ${parsedData.args.id}: ${err.message}`);
peer.write(JSON.stringify({ error: `Log stream error: ${err.message}` }));
});
break;
case 'duplicateContainer':
console.log('[INFO] Handling \'duplicateContainer\' command');
const { name, image, hostname, netmode, cpu, memory, config: dupConfig } = parsedData.args;