frontend/src/components/Logs.vue
<template>
<div class="logs-container">
<div class="logs-header">
<span>Logs: {{ selectedPod?.metadata?.name }}</span>
<button @click="$emit('close')" class="close-btn">×</button>
</div>
<div class="logs-content" ref="logsContent">
<pre v-html="logContent"></pre>
</div>
</div>
</template>
<script>
export default {
name: 'Logs',
props: {
selectedPod: {
type: Object,
required: true
},
selectedNamespace: {
type: Object,
required: true
},
selectedCluster: {
type: Object,
required: true
},
selectedContainer: {
type: String,
required: true
}
},
data() {
return {
socket: null,
logContent: '',
isConnected: false,
reconnectAttempts: 0,
maxReconnectAttempts: 3,
isReconnecting: false
}
},
mounted() {
this.connectWebSocket();
},
beforeUnmount() {
this.cleanup();
},
methods: {
connectWebSocket() {
if (this.isReconnecting) {
return;
}
this.isReconnecting = true;
if (this.socket) {
this.socket.close();
this.socket = null;
}
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${wsProtocol}//${window.location.hostname}:8081/api/pods/logs?` +
`cluster=${encodeURIComponent(this.selectedCluster.server)}&` +
`namespace=${encodeURIComponent(this.selectedNamespace.name)}&` +
`pod=${encodeURIComponent(this.selectedPod.metadata.name)}&` +
`container=${encodeURIComponent(this.selectedContainer)}`;
try {
this.socket = new WebSocket(wsUrl);
this.socket.onopen = () => {
this.isConnected = true;
this.reconnectAttempts = 0;
this.isReconnecting = false;
this.logContent += 'Connected to pod logs...\n';
this.scrollToBottom();
};
this.socket.onmessage = (event) => {
this.logContent += event.data;
this.scrollToBottom();
};
this.socket.onclose = () => {
this.isConnected = false;
this.isReconnecting = false;
this.logContent += '\nConnection closed\n';
this.scrollToBottom();
};
this.socket.onerror = (error) => {
console.error('WebSocket error:', error);
this.isReconnecting = false;
this.logContent += '\nError: Failed to connect to pod logs\n';
this.scrollToBottom();
};
} catch (error) {
console.error('Failed to connect to WebSocket:', error);
this.isReconnecting = false;
this.logContent += 'Failed to connect to pod logs\n';
this.scrollToBottom();
}
},
scrollToBottom() {
if (this.$refs.logsContent) {
this.$refs.logsContent.scrollTop = this.$refs.logsContent.scrollHeight;
}
},
cleanup() {
if (this.socket) {
this.socket.close();
this.socket = null;
}
this.isConnected = false;
this.isReconnecting = false;
this.reconnectAttempts = 0;
}
}
}
</script>
<style scoped>
.logs-container {
position: fixed;
bottom: 20px;
right: 20px;
width: 800px;
height: 500px;
background: #1e1e1e;
border: 1px solid #333;
border-radius: 6px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
z-index: 1000;
display: flex;
flex-direction: column;
overflow: hidden;
}
.logs-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
background: #333;
color: white;
font-size: 14px;
user-select: none;
}
.close-btn {
background: none;
border: none;
color: white;
font-size: 20px;
cursor: pointer;
padding: 0 4px;
line-height: 1;
}
.close-btn:hover {
color: #ff5252;
}
.logs-content {
flex: 1;
padding: 12px;
overflow-y: auto;
background-color: #1e1e1e;
color: #ffffff;
font-family: monospace;
white-space: pre-wrap;
word-wrap: break-word;
text-align: left;
}
pre {
margin: 0;
font-size: 12px;
line-height: 1.4;
}
</style>