Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion agent/app/service/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -834,7 +834,7 @@ func collectLogs(params dto.StreamLog, messageChan chan<- string, errorChan chan
if params.Follow {
cmdArgs = append(cmdArgs, "-f")
}
if params.Tail != "all" {
if params.Tail != "0" {
cmdArgs = append(cmdArgs, "--tail", params.Tail)
}
if params.Since != "all" {
Expand Down
41 changes: 32 additions & 9 deletions frontend/src/components/container-log/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,26 @@
{{ $t('commons.button.clean') }}
</el-button>
</div>
<div class="log-container" ref="logContainer">
<!-- <div class="log-container" ref="logContainer">
<DynamicScroller :items="logs" :min-item-size="32" v-if="logs.length">
<template #default="{ item, active }">
<DynamicScrollerItem
:item="item"
:active="active"
class="msgBox"
:size-dependencies="[item]"
:data-index="item"
>
<span class="log-item">{{ item }}</span>
<DynamicScrollerItem :item="item" :active="active" :size-dependencies="[item]" :data-index="item">
<hightlight :log="item" type="container"></hightlight>
</DynamicScrollerItem>
</template>
</DynamicScroller>
</div> -->

<div class="log-container" ref="logContainer">
<div class="log-spacer" :style="{ height: `${totalHeight}px` }"></div>
<div
v-for="(log, index) in visibleLogs"
:key="startIndex + index"
class="log-item"
:style="{ top: `${(startIndex + index) * logHeight}px` }"
>
<hightlight :log="log" type="container"></hightlight>
</div>
</div>
</template>

Expand All @@ -48,6 +54,7 @@ import { dateFormatForName } from '@/utils/util';
import { onUnmounted, reactive, ref } from 'vue';
import { ElMessageBox } from 'element-plus';
import { MsgError, MsgSuccess } from '@/utils/message';
import hightlight from '@/components/hightlight/index.vue';

const props = defineProps({
container: {
Expand All @@ -71,6 +78,15 @@ const logSearch = reactive({
tail: 100,
compose: '',
});
const logHeight = 20;
const logCount = ref(0);
const totalHeight = computed(() => logHeight * logCount.value);
const startIndex = ref(0);
const containerHeight = ref(500);
const visibleCount = computed(() => Math.ceil(containerHeight.value / logHeight));
const visibleLogs = computed(() => {
return logs.value.slice(startIndex.value, startIndex.value + visibleCount.value);
});

const timeOptions = ref([
{ label: i18n.global.t('container.all'), value: 'all' },
Expand Down Expand Up @@ -178,6 +194,13 @@ onMounted(() => {
logSearch.mode = 'all';
logSearch.isWatch = true;

nextTick(() => {
if (logContainer.value) {
logContainer.value.scrollTop = totalHeight.value;
containerHeight.value = logContainer.value.getBoundingClientRect().height;
}
});

searchLogs();
});
</script>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provided changes do not introduce significant issues but suggest room for improvement and further optimizations. It would be beneficial to refactor such that it looks more consistent with modern Vue practices. Currently, the use of hightlight component does not seem necessary since it's imported from another file. Additionally, there might be unnecessary comments or redundant logic.

Here is a refined version:

<template>
  <div ref="logContainer">
    <!-- ... rest of the template -->
  </div>
</template>

<script lang="ts">
import { defineComponent, PropType } from 'vue';
import { onMounted, watchEffect, computed } from 'vue';

// ...

export default defineComponent({
  name: '',
  setup(props:any) {

    // ...
  },
});
</script>

Expand Down
220 changes: 220 additions & 0 deletions frontend/src/components/hightlight/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
<template>
<span v-for="(token, index) in tokens" :key="index" :class="['token', token.type]" :style="{ color: token.color }">
{{ token.text }}
</span>
</template>
<script setup lang="ts">
interface TokenRule {
type: string;
pattern: RegExp;
color: string;
}
interface Token {
text: string;
type: string;
color: string;
}
const props = defineProps<{
log: string;
type: string;
}>();
let rules = ref<TokenRule[]>([]);
const nginxRules: TokenRule[] = [
{
type: 'log-level',
pattern: /\[(error|warn|notice|info|debug)\]/gi,
color: '#E74C3C',
},
{
type: 'path',
pattern:
/(?:(?<=GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)\s+|(?<=open\(\s*")|(?<="\s*))(\/[^"\s]+(?:\.\w+)?(?:\?\w+=\w+)?)/g,
color: '#B87A2B',
},
{
type: 'http-method',
pattern: /(?<=")(?:GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)(?=\s)/g,
color: '#27AE60',
},
{
type: 'status-success',
pattern: /\s(2\d{2})\s/g,
color: '#2ECC71',
},
{
type: 'status-error',
pattern: /\s([45]\d{2})\s/g,
color: '#E74C3C',
},
{
type: 'process-info',
pattern: /\d+#\d+/g,
color: '#7F8C8D',
},
];
const systemRules: TokenRule[] = [
{
type: 'log-error',
pattern: /\[(ERROR|WARN|FATAL)\]/g,
color: '#E74C3C',
},
{
type: 'log-normal',
pattern: /\[(INFO|DEBUG)\]/g,
color: '#8B8B8B',
},
{
type: 'timestamp',
pattern: /\[\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\]/g,
color: '#8B8B8B',
},
{
type: 'bracket-text',
pattern: /\[([^\]]+)\]/g,
color: '#B87A2B',
},
{
type: 'referrer-ua',
pattern: /https?:\/\/(?:[\w-]+\.)+[\w-]+(?::\d+)?(?:\/[^\s\]\)"]*)?/g,
color: '#786C88',
},
];
const taskRules: TokenRule[] = [
{
type: 'bracket-text',
pattern: /\[([^\]]+)\]/g,
color: '#B87A2B',
},
];
const defaultRules: TokenRule[] = [
{
type: 'timestamp',
pattern:
/(?:\[\d{2}\/\w{3}\/\d{4}:\d{2}:\d{2}:\d{2}\s[+-]\d{4}\]|\d{4}[-\/]\d{2}[-\/]\d{2}\s\d{2}:\d{2}:\d{2})/g,
color: '#8B8B8B',
},
{
type: 'referrer-ua',
pattern: /"(?:https?:\/\/[^"]+|Mozilla[^"]+|curl[^"]+)"/g,
color: '#786C88',
},
{
type: 'ip',
pattern: /\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/g,
color: '#4A90E2',
},
{
type: 'server-host',
pattern: /(?:server|host):\s*[^,\s]+/g,
color: '#5D6D7E',
},
];
const containerRules: TokenRule[] = [
{
type: 'timestamp',
pattern: /\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}\+\d{2}:\d{2}/g,
color: '#8B8B8B',
},
{
type: 'bracket-text',
pattern: /\[([^\]]+)\]/g,
color: '#B87A2B',
},
];
function tokenizeLog(log: string): Token[] {
const tokens: Token[] = [];
let lastIndex = 0;
let matches: { index: number; text: string; type: string; color: string }[] = [];
rules.value.forEach((rule) => {
const regex = new RegExp(rule.pattern.source, 'g');
let match;
while ((match = regex.exec(log)) !== null) {
matches.push({
index: match.index,
text: match[0],
type: rule.type,
color: rule.color,
});
}
});
matches.sort((a, b) => a.index - b.index);
matches = matches.filter((match, index) => {
if (index === 0) return true;
const prev = matches[index - 1];
return match.index >= prev.index + prev.text.length;
});
matches.forEach((match) => {
if (match.index > lastIndex) {
tokens.push({
text: log.substring(lastIndex, match.index),
type: 'plain',
color: '#666666',
});
}
tokens.push({
text: match.text,
type: match.type,
color: match.color,
});
lastIndex = match.index + match.text.length;
});
if (lastIndex < log.length) {
tokens.push({
text: log.substring(lastIndex),
type: 'plain',
color: '#666666',
});
}
return tokens;
}
const tokens = computed(() => tokenizeLog(props.log));
onMounted(() => {
switch (props.type) {
case 'nginx':
rules.value = nginxRules.concat(defaultRules);
break;
case 'system':
rules.value = systemRules.concat(defaultRules);
break;
case 'container':
rules.value = containerRules.concat(defaultRules);
break;
case 'task':
rules.value = taskRules.concat(defaultRules);
break;
default:
rules.value = defaultRules;
break;
}
});
</script>

<style scoped>
.token {
font-family: 'JetBrains Mono', Monaco, Menlo, Consolas, 'Courier New', monospace;
font-size: 14px;
font-weight: 500;
}
.ip {
text-decoration: underline;
text-decoration-style: dotted;
text-decoration-thickness: 1px;
}
</style>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on my knowledge as of September 2021, there is no evident irregularity or issue with this code snippet. The syntax and structure appear to be sound, the use of variables such as rules seems appropriate and consistent throughout, and each component of this React application follows good practices for its specific functionality.

However, I would like to make some generic optimization suggestions that could potentially add value:

  1. Code Formatting: Ensure consistency in formatting, which might include adding tabs instead of spaces when indentation.
  2. Refactoring: Consider reorganizing components for better clarity or to maintain a clean separation of concerns between components or services used by them.
  3. Commenting: If possible, enhance documentation within the script to explain the logic behind certain decisions made during development, especially about design choices like how different sets of rules interact with one another and their purpose in generating tokens from log entries.

Remember that these are general tips based solely on past experiences and should not replace actual debugging techniques or best coding practices. It's always important to analyze code thoroughly to understand the nuances, including those hidden under comments but difficult to uncover without proper context.

12 changes: 10 additions & 2 deletions frontend/src/components/log-file/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
class="log-item"
:style="{ top: `${(startIndex + index) * logHeight}px` }"
>
<span>{{ log }}</span>
<hightlight :log="log" :type="config.colorMode"></hightlight>
</div>
</div>
</div>
Expand All @@ -36,6 +36,7 @@ import { downloadFile } from '@/utils/util';
import { ReadByLine } from '@/api/modules/files';
import { GlobalStore } from '@/store';
import bus from '@/global/bus';
import hightlight from '@/components/hightlight/index.vue';
const globalStore = GlobalStore();

interface LogProps {
Expand All @@ -44,6 +45,7 @@ interface LogProps {
name?: string;
tail?: boolean;
taskID?: string;
colorMode?: string;
}

const props = defineProps({
Expand All @@ -54,6 +56,7 @@ const props = defineProps({
type: '',
name: '',
tail: false,
colorMode: 'nginx',
}),
},
defaultButton: {
Expand Down Expand Up @@ -315,7 +318,7 @@ defineExpose({ changeTail, onDownload, clearLog });
</script>
<style lang="scss" scoped>
.log-container {
height: calc(100vh - 405px);
height: calc(100vh - 420px);
overflow-y: auto;
overflow-x: auto;
position: relative;
Expand All @@ -336,4 +339,9 @@ defineExpose({ changeTail, onDownload, clearLog });
box-sizing: border-box;
white-space: nowrap;
}

.log-content {
font-size: 14px;
line-height: 20px;
}
</style>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There aren't any obvious issues or regularities in the given CSS code snippet. It seems to be perfectly valid and consistent in terms of its layout, formatting styles, etc.

However, keep in mind that this is not an exhaustive assessment of all potential concerns with regard to style guidelines best practices and web accessibility standards.

Here's what you might want to consider:

  • Color Selection: There doesn't seem to be much inconsistency regarding color usage across different parts of the code. However, it's always essential to validate against accessibility guidelines for proper contrast ratios among text elements.

  • Layout Consistency: The CSS properties like top, height, and overflow-y have consistently been applied throughout the document. But consistency in font-family choice (both inside <style> tags and outside them) could help ensure readability across multiple files.

Keep refining these small details based on specific needs and industry best practices if applicable to your project scope!

1 change: 1 addition & 0 deletions frontend/src/components/task-log/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const config = reactive({
resourceID: 0,
taskType: '',
tail: true,
colorMode: 'task',
});
const open = ref(false);
const showTail = ref(true);
Expand Down
1 change: 1 addition & 0 deletions frontend/src/views/log/system/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const hasContent = ref(false);
const logConfig = reactive({
type: 'system',
name: '',
colorMode: 'system',
});
const showLog = ref(false);

Expand Down
1 change: 1 addition & 0 deletions frontend/src/views/log/website/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ const logConfig = reactive({
type: 'website',
id: undefined,
name: 'access.log',
colorMode: 'nginx',
});
const showLog = ref(false);
const loading = ref(false);
Expand Down
Loading
Loading