2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 04:22:33 +08:00

fix: 修正日志样式

This commit is contained in:
2026-01-13 19:32:03 +08:00
parent 4dc21b5443
commit d0b3c14421
7 changed files with 193 additions and 4 deletions

View File

@@ -39,6 +39,7 @@
"@xterm/xterm": "^6.0.0",
"alova": "^3.3.4",
"echarts": "^6.0.0",
"highlight.js": "^11.11.1",
"install": "^0.13.0",
"lodash-es": "^4.17.21",
"luxon": "^3.7.2",

3
web/pnpm-lock.yaml generated
View File

@@ -50,6 +50,9 @@ importers:
echarts:
specifier: ^6.0.0
version: 6.0.0
highlight.js:
specifier: ^11.11.1
version: 11.11.1
install:
specifier: ^0.13.0
version: 0.13.0

View File

@@ -1,6 +1,13 @@
<script lang="ts" setup>
import systemdlog from '@/utils/hljs/systemdlog'
import hljs from 'highlight.js/lib/core'
import log from 'highlight.js/lib/languages/accesslog'
import { useThemeStore } from '@/store'
hljs.registerLanguage('accesslog', log)
hljs.registerLanguage('systemdlog', systemdlog)
const themeStore = useThemeStore()
watch(
@@ -29,6 +36,7 @@ onBeforeUnmount(() => {
<template>
<n-config-provider
:hljs="hljs"
:theme="themeStore.naiveTheme"
:locale="themeStore.naiveLocale"
:date-locale="themeStore.naiveDateLocale"

View File

@@ -12,6 +12,11 @@ const props = defineProps({
service: {
type: String,
required: false
},
language: {
type: String,
required: false,
default: 'systemdlog'
}
})
@@ -82,7 +87,7 @@ defineExpose({
</script>
<template>
<n-log ref="logRef" :log="log" trim :rows="40" />
<n-log ref="logRef" :log="log" trim :rows="40" :language="props.language" />
</template>
<style scoped lang="scss"></style>

View File

@@ -9,6 +9,11 @@ const props = defineProps({
path: {
type: String,
required: true
},
language: {
type: String,
required: false,
default: 'systemdlog'
}
})
@@ -72,7 +77,7 @@ defineExpose({
@close="handleClose"
@mask-click="handleClose"
>
<n-log ref="logRef" :log="log" trim :rows="40" />
<n-log ref="logRef" :log="log" trim :rows="40" :language="props.language" />
</n-modal>
</template>

View File

@@ -0,0 +1,167 @@
/*
Language: systemd Journal (journalctl)
Description: systemd/journald logs (journalctl -o short / short-iso)
Category: system, logs
*/
/** @type {import('highlight.js').LanguageFn} */
export default function systemdJournal(hljs: any) {
const regex = hljs.regex
// Month names for "short" format
const MONTH = '(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)'
// journalctl -o short:
// Jan 13 10:22:33 ...
const TS_SHORT = new RegExp(`^${MONTH}\\s+\\d{1,2}\\s+\\d{2}:\\d{2}:\\d{2}`)
// journalctl -o short-iso:
// 2026-01-13T10:22:33+0800 ...
// 2026-01-13 10:22:33 ...
const TS_ISO = /^\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?/
const HOST = /[A-Za-z0-9][A-Za-z0-9_.-]*/
const IDENT = /[A-Za-z_][A-Za-z0-9_.-]*(?:\/[A-Za-z0-9_.-]+)*/ // e.g. systemd, sshd, foo/bar
const PID_OPT = /(?:\[\d+\])?/
const UNIT = /\b[\w.-]+?\.(?:service|socket|target|timer|mount|device|path|slice|scope)\b/
const PRIORITY_WORDS = [
'emerg',
'alert',
'crit',
'critical',
'err',
'error',
'warn',
'warning',
'notice',
'info',
'debug',
'panic',
// systemd/journal 常见状态词
'failed',
'failure',
'timeout',
'timed',
'denied',
'refused',
'segfault'
]
const SYSTEMD_VERBS = [
'starting',
'started',
'stopping',
'stopped',
'reloading',
'reloaded',
'restarting',
'restarted',
'activating',
'activated',
'deactivating',
'deactivated',
'mounted',
'mounting',
'unmounted',
'unmounting',
'listening',
'triggered',
'queued',
'succeeded',
'success'
]
// Prefix: "<timestamp> <host> <ident>[pid]: "
// Example:
// Jan 13 10:22:33 host systemd[1]:
// 2026-01-13T10:22:33+0800 host sshd[1234]:
const PREFIX = {
begin: [regex.either(TS_ISO, TS_SHORT), /\s+/, HOST, /\s+/, IDENT, PID_OPT],
beginScope: {
1: 'meta', // timestamp
3: 'title', // hostname
5: 'symbol', // identifier
6: 'number' // [pid]
},
end: /: /,
endScope: 'punctuation',
relevance: 10
}
const SEVERITY = {
match: new RegExp(`\\b(?:${PRIORITY_WORDS.join('|')})\\b`, 'i'),
scope: 'keyword',
relevance: 2
}
const STATUS_VERB = {
match: new RegExp(`\\b(?:${SYSTEMD_VERBS.join('|')})\\b`, 'i'),
scope: 'built_in',
relevance: 1
}
// key=valuecode=exited status=1/FAILURE UNIT=foo.service
const KEY_VALUE = {
begin: /\b[\w.-]+=/,
scope: 'attr',
relevance: 0
}
// kernel/journal 常见的 monotonic timestamp: "[ 123.456]"
const MONOTONIC = {
match: /\[\s*\d+(?:\.\d+)?\]/,
scope: 'meta',
relevance: 0
}
const DQUOTE = {
scope: 'string',
begin: /"/,
end: /"/,
illegal: /\n/,
relevance: 0
}
const SQUOTE = {
scope: 'string',
begin: /'/,
end: /'/,
illegal: /\n/,
relevance: 0
}
const PATH = {
match: /(?:\/[^\s"'():\[\]]+)+/,
scope: 'string',
relevance: 0
}
return {
name: 'systemd Journal',
aliases: ['journalctl', 'journald', 'systemdlog', 'systemd-journal', 'systemd'],
case_insensitive: true,
contains: [
PREFIX,
// unit names in message body
{ match: UNIT, scope: 'title', relevance: 3 },
// severity/status words
SEVERITY,
STATUS_VERB,
MONOTONIC,
KEY_VALUE,
// numbers (exit codes, pids, etc.)
hljs.NUMBER_MODE,
// strings/paths
DQUOTE,
SQUOTE,
PATH
]
}
}

View File

@@ -912,7 +912,7 @@ const updateTimeoutUnit = (proxy: any, unit: string) => {
{{ $gettext('Are you sure you want to clear?') }}
</n-popconfirm>
</n-flex>
<realtime-log :path="setting.access_log" />
<realtime-log :path="setting.access_log" language="accesslog" />
</n-flex>
</n-tab-pane>
<n-tab-pane name="error_log" :tab="$gettext('Error Log')">
@@ -924,7 +924,7 @@ const updateTimeoutUnit = (proxy: any, unit: string) => {
{{ $gettext('view') }}.
</n-alert>
</n-flex>
<realtime-log :path="setting.error_log" />
<realtime-log :path="setting.error_log" language="accesslog" />
</n-flex>
</n-tab-pane>
</n-tabs>