feat(nginx_log): add basic log_list fallback when AdvancedIndexing is disabled

- Introduce in-memory fallback cache and simple rotation grouping
- Route AddLogPath/RemoveLogPathsFromConfig/Get* to fallback when LogFileManager is unavailable
- Preserve existing behavior when AdvancedIndexingEnabled is true
This commit is contained in:
0xJacky
2025-10-01 04:03:59 +00:00
parent 09bf16c8b8
commit 9124b33cf3
27 changed files with 532 additions and 269 deletions
+86 -13
View File
@@ -103,18 +103,91 @@ declare global {
}
// for vue template auto import
type UnwrapRefs<T> = {
[K in keyof T]: import('vue').UnwrapRef<T[K]>
}
namespace _ComponentCustomProperties {
const { $gettext, $ngettext, $npgettext, $pgettext }: typeof import('@/gettext')
const { App }: typeof import('ant-design-vue')
const { EffectScope, computed, createApp, customRef, defineAsyncComponent, defineComponent, effectScope, getCurrentInstance, getCurrentScope, getCurrentWatcher, h, inject, isProxy, isReactive, isReadonly, isRef, isShallow, markRaw, nextTick, onActivated, onBeforeMount, onBeforeUnmount, onBeforeUpdate, onDeactivated, onErrorCaptured, onMounted, onRenderTracked, onRenderTriggered, onScopeDispose, onServerPrefetch, onUnmounted, onUpdated, onWatcherCleanup, provide, reactive, readonly, ref, resolveComponent, shallowReactive, shallowReadonly, shallowRef, toRaw, toRef, toRefs, toValue, triggerRef, unref, useAttrs, useCssModule, useCssVars, useId, useModel, useSlots, useTemplateRef, watch, watchEffect, watchPostEffect, watchSyncEffect }: typeof import('vue')
const { T }: typeof import('@/language')
const { acceptHMRUpdate, createPinia, defineStore, getActivePinia, mapActions, mapGetters, mapState, mapStores, mapWritableState, setActivePinia, setMapStoreSuffix, storeToRefs }: typeof import('pinia')
const { onBeforeRouteLeave, onBeforeRouteUpdate, useLink, useRoute, useRouter }: typeof import('vue-router')
const { useGlobalApp }: typeof import('@/composables/useGlobalApp')
}
import { UnwrapRef } from 'vue'
declare module 'vue' {
interface ComponentCustomProperties extends UnwrapRefs<typeof _ComponentCustomProperties> {}
interface GlobalComponents {}
interface ComponentCustomProperties {
readonly $gettext: UnwrapRef<typeof import('@/gettext')['$gettext']>
readonly $ngettext: UnwrapRef<typeof import('@/gettext')['$ngettext']>
readonly $npgettext: UnwrapRef<typeof import('@/gettext')['$npgettext']>
readonly $pgettext: UnwrapRef<typeof import('@/gettext')['$pgettext']>
readonly App: UnwrapRef<typeof import('ant-design-vue')['App']>
readonly EffectScope: UnwrapRef<typeof import('vue')['EffectScope']>
readonly T: UnwrapRef<typeof import('@/language')['T']>
readonly acceptHMRUpdate: UnwrapRef<typeof import('pinia')['acceptHMRUpdate']>
readonly computed: UnwrapRef<typeof import('vue')['computed']>
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
readonly createPinia: UnwrapRef<typeof import('pinia')['createPinia']>
readonly customRef: UnwrapRef<typeof import('vue')['customRef']>
readonly defineAsyncComponent: UnwrapRef<typeof import('vue')['defineAsyncComponent']>
readonly defineComponent: UnwrapRef<typeof import('vue')['defineComponent']>
readonly defineStore: UnwrapRef<typeof import('pinia')['defineStore']>
readonly effectScope: UnwrapRef<typeof import('vue')['effectScope']>
readonly getActivePinia: UnwrapRef<typeof import('pinia')['getActivePinia']>
readonly getCurrentInstance: UnwrapRef<typeof import('vue')['getCurrentInstance']>
readonly getCurrentScope: UnwrapRef<typeof import('vue')['getCurrentScope']>
readonly getCurrentWatcher: UnwrapRef<typeof import('vue')['getCurrentWatcher']>
readonly h: UnwrapRef<typeof import('vue')['h']>
readonly inject: UnwrapRef<typeof import('vue')['inject']>
readonly isProxy: UnwrapRef<typeof import('vue')['isProxy']>
readonly isReactive: UnwrapRef<typeof import('vue')['isReactive']>
readonly isReadonly: UnwrapRef<typeof import('vue')['isReadonly']>
readonly isRef: UnwrapRef<typeof import('vue')['isRef']>
readonly isShallow: UnwrapRef<typeof import('vue')['isShallow']>
readonly mapActions: UnwrapRef<typeof import('pinia')['mapActions']>
readonly mapGetters: UnwrapRef<typeof import('pinia')['mapGetters']>
readonly mapState: UnwrapRef<typeof import('pinia')['mapState']>
readonly mapStores: UnwrapRef<typeof import('pinia')['mapStores']>
readonly mapWritableState: UnwrapRef<typeof import('pinia')['mapWritableState']>
readonly markRaw: UnwrapRef<typeof import('vue')['markRaw']>
readonly nextTick: UnwrapRef<typeof import('vue')['nextTick']>
readonly onActivated: UnwrapRef<typeof import('vue')['onActivated']>
readonly onBeforeMount: UnwrapRef<typeof import('vue')['onBeforeMount']>
readonly onBeforeRouteLeave: UnwrapRef<typeof import('vue-router')['onBeforeRouteLeave']>
readonly onBeforeRouteUpdate: UnwrapRef<typeof import('vue-router')['onBeforeRouteUpdate']>
readonly onBeforeUnmount: UnwrapRef<typeof import('vue')['onBeforeUnmount']>
readonly onBeforeUpdate: UnwrapRef<typeof import('vue')['onBeforeUpdate']>
readonly onDeactivated: UnwrapRef<typeof import('vue')['onDeactivated']>
readonly onErrorCaptured: UnwrapRef<typeof import('vue')['onErrorCaptured']>
readonly onMounted: UnwrapRef<typeof import('vue')['onMounted']>
readonly onRenderTracked: UnwrapRef<typeof import('vue')['onRenderTracked']>
readonly onRenderTriggered: UnwrapRef<typeof import('vue')['onRenderTriggered']>
readonly onScopeDispose: UnwrapRef<typeof import('vue')['onScopeDispose']>
readonly onServerPrefetch: UnwrapRef<typeof import('vue')['onServerPrefetch']>
readonly onUnmounted: UnwrapRef<typeof import('vue')['onUnmounted']>
readonly onUpdated: UnwrapRef<typeof import('vue')['onUpdated']>
readonly onWatcherCleanup: UnwrapRef<typeof import('vue')['onWatcherCleanup']>
readonly provide: UnwrapRef<typeof import('vue')['provide']>
readonly reactive: UnwrapRef<typeof import('vue')['reactive']>
readonly readonly: UnwrapRef<typeof import('vue')['readonly']>
readonly ref: UnwrapRef<typeof import('vue')['ref']>
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
readonly setActivePinia: UnwrapRef<typeof import('pinia')['setActivePinia']>
readonly setMapStoreSuffix: UnwrapRef<typeof import('pinia')['setMapStoreSuffix']>
readonly shallowReactive: UnwrapRef<typeof import('vue')['shallowReactive']>
readonly shallowReadonly: UnwrapRef<typeof import('vue')['shallowReadonly']>
readonly shallowRef: UnwrapRef<typeof import('vue')['shallowRef']>
readonly storeToRefs: UnwrapRef<typeof import('pinia')['storeToRefs']>
readonly toRaw: UnwrapRef<typeof import('vue')['toRaw']>
readonly toRef: UnwrapRef<typeof import('vue')['toRef']>
readonly toRefs: UnwrapRef<typeof import('vue')['toRefs']>
readonly toValue: UnwrapRef<typeof import('vue')['toValue']>
readonly triggerRef: UnwrapRef<typeof import('vue')['triggerRef']>
readonly unref: UnwrapRef<typeof import('vue')['unref']>
readonly useAttrs: UnwrapRef<typeof import('vue')['useAttrs']>
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
readonly useCssVars: UnwrapRef<typeof import('vue')['useCssVars']>
readonly useGlobalApp: UnwrapRef<typeof import('@/composables/useGlobalApp')['useGlobalApp']>
readonly useId: UnwrapRef<typeof import('vue')['useId']>
readonly useLink: UnwrapRef<typeof import('vue-router')['useLink']>
readonly useModel: UnwrapRef<typeof import('vue')['useModel']>
readonly useRoute: UnwrapRef<typeof import('vue-router')['useRoute']>
readonly useRouter: UnwrapRef<typeof import('vue-router')['useRouter']>
readonly useSlots: UnwrapRef<typeof import('vue')['useSlots']>
readonly useTemplateRef: UnwrapRef<typeof import('vue')['useTemplateRef']>
readonly watch: UnwrapRef<typeof import('vue')['watch']>
readonly watchEffect: UnwrapRef<typeof import('vue')['watchEffect']>
readonly watchPostEffect: UnwrapRef<typeof import('vue')['watchPostEffect']>
readonly watchSyncEffect: UnwrapRef<typeof import('vue')['watchSyncEffect']>
}
}
+5
View File
@@ -20,6 +20,9 @@ declare module 'vue' {
ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup']
ACol: typeof import('ant-design-vue/es')['Col']
ACollapse: typeof import('ant-design-vue/es')['Collapse']
ACollapsePanel: typeof import('ant-design-vue/es')['CollapsePanel']
AComment: typeof import('ant-design-vue/es')['Comment']
AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider']
ADivider: typeof import('ant-design-vue/es')['Divider']
ADrawer: typeof import('ant-design-vue/es')['Drawer']
@@ -40,6 +43,7 @@ declare module 'vue' {
AListItem: typeof import('ant-design-vue/es')['ListItem']
AListItemMeta: typeof import('ant-design-vue/es')['ListItemMeta']
AMenu: typeof import('ant-design-vue/es')['Menu']
AMenuDivider: typeof import('ant-design-vue/es')['MenuDivider']
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
AModal: typeof import('ant-design-vue/es')['Modal']
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
@@ -60,6 +64,7 @@ declare module 'vue' {
ATabPane: typeof import('ant-design-vue/es')['TabPane']
ATabs: typeof import('ant-design-vue/es')['Tabs']
ATag: typeof import('ant-design-vue/es')['Tag']
ATextarea: typeof import('ant-design-vue/es')['Textarea']
ATooltip: typeof import('ant-design-vue/es')['Tooltip']
ATypographyText: typeof import('ant-design-vue/es')['TypographyText']
ATypographyTitle: typeof import('ant-design-vue/es')['TypographyTitle']
+9 -9
View File
@@ -483,7 +483,7 @@ msgstr "فشل النسخ الاحتياطي التلقائي"
msgid "Auto Backup Storage Failed"
msgstr "فشل تخزين النسخ الاحتياطي التلقائي"
#: src/views/nginx_log/NginxLog.vue:64 src/views/node/Node.vue:164
#: src/views/nginx_log/NginxLog.vue:86 src/views/node/Node.vue:164
msgid "Auto Refresh"
msgstr "التحديث التلقائي"
@@ -535,7 +535,7 @@ msgstr "متوسط/زيارة الصفحة"
#: src/views/certificate/components/CertificateActions.vue:22
#: src/views/config/components/ConfigLeftPanel.vue:273
#: src/views/config/ConfigList.vue:120 src/views/config/ConfigList.vue:217
#: src/views/nginx_log/NginxLog.vue:92
#: src/views/nginx_log/NginxLog.vue:114
#: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:170
#: src/views/stream/components/StreamEditor.vue:134
msgid "Back"
@@ -1519,7 +1519,7 @@ msgstr "يوميًا في الساعة %{time}"
#: src/routes/modules/dashboard.ts:10
#: src/views/config/components/ConfigLeftPanel.vue:109
#: src/views/config/components/ConfigLeftPanel.vue:159
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:56
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:78
msgid "Dashboard"
msgstr "لوحة المعلومات"
@@ -2741,11 +2741,11 @@ msgstr "تم تحميل الملف بنجاح"
msgid "Filename is empty"
msgstr "اسم الملف فارغ"
#: src/views/nginx_log/raw/RawLogViewer.vue:155
#: src/views/nginx_log/raw/RawLogViewer.vue:298
msgid "Filter"
msgstr "تصفيه"
#: src/views/nginx_log/raw/RawLogViewer.vue:158
#: src/views/nginx_log/raw/RawLogViewer.vue:301
msgid "Filter log content"
msgstr "تصفية محتوى السجل"
@@ -4065,7 +4065,7 @@ msgstr "إن Nginx لا يعمل في حاوية أخرى"
msgid "Nginx is running"
msgstr "إن Nginx يعمل"
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:39
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:61
msgid "Nginx Log"
msgstr "سجل Nginx"
@@ -4963,7 +4963,7 @@ msgstr "في قائمة انتظار الفهرسة..."
msgid "Quick Select"
msgstr "اختيار سريع"
#: src/views/nginx_log/NginxLog.vue:57
#: src/views/nginx_log/NginxLog.vue:79
msgid "Raw"
msgstr "خام"
@@ -6078,7 +6078,7 @@ msgstr "دليل Streams-available غير موجود"
msgid "Streams-enabled directory not exist"
msgstr "دليل Streams-enabled غير موجود"
#: src/views/nginx_log/NginxLog.vue:55
#: src/views/nginx_log/NginxLog.vue:77
msgid "Structured"
msgstr "منظم"
@@ -7175,7 +7175,7 @@ msgstr "كتابة الشهادة إلى القرص"
msgid "Yes"
msgstr "نعم"
#: src/views/terminal/Terminal.vue:201
#: src/views/terminal/Terminal.vue:200
msgid ""
"You are accessing this terminal over an insecure HTTP connection on a non-"
"localhost domain. This may expose sensitive information."
+9 -9
View File
@@ -495,7 +495,7 @@ msgstr "Automatische Sicherung fehlgeschlagen"
msgid "Auto Backup Storage Failed"
msgstr "Automatische Sicherungsspeicherung fehlgeschlagen"
#: src/views/nginx_log/NginxLog.vue:64 src/views/node/Node.vue:164
#: src/views/nginx_log/NginxLog.vue:86 src/views/node/Node.vue:164
msgid "Auto Refresh"
msgstr "Automatische Aktualisierung"
@@ -547,7 +547,7 @@ msgstr "Durchschn./PV"
#: src/views/certificate/components/CertificateActions.vue:22
#: src/views/config/components/ConfigLeftPanel.vue:273
#: src/views/config/ConfigList.vue:120 src/views/config/ConfigList.vue:217
#: src/views/nginx_log/NginxLog.vue:92
#: src/views/nginx_log/NginxLog.vue:114
#: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:170
#: src/views/stream/components/StreamEditor.vue:134
msgid "Back"
@@ -1552,7 +1552,7 @@ msgstr "Täglich um %{time}"
#: src/routes/modules/dashboard.ts:10
#: src/views/config/components/ConfigLeftPanel.vue:109
#: src/views/config/components/ConfigLeftPanel.vue:159
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:56
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:78
msgid "Dashboard"
msgstr "Übersicht"
@@ -2788,11 +2788,11 @@ msgstr "Datei erfolgreich hochgeladen"
msgid "Filename is empty"
msgstr "Der Dateiname ist leer"
#: src/views/nginx_log/raw/RawLogViewer.vue:155
#: src/views/nginx_log/raw/RawLogViewer.vue:298
msgid "Filter"
msgstr "Filter"
#: src/views/nginx_log/raw/RawLogViewer.vue:158
#: src/views/nginx_log/raw/RawLogViewer.vue:301
msgid "Filter log content"
msgstr "Loginhalt filtern"
@@ -4125,7 +4125,7 @@ msgstr "Nginx läuft nicht in einem anderen Container"
msgid "Nginx is running"
msgstr "Nginx läuft"
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:39
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:61
msgid "Nginx Log"
msgstr "Nginx-Log"
@@ -5049,7 +5049,7 @@ msgstr "Zur Indizierung in der Warteschlange..."
msgid "Quick Select"
msgstr "Schnellauswahl"
#: src/views/nginx_log/NginxLog.vue:57
#: src/views/nginx_log/NginxLog.vue:79
msgid "Raw"
msgstr "Roh"
@@ -6185,7 +6185,7 @@ msgstr "Streams-available-Verzeichnis existiert nicht"
msgid "Streams-enabled directory not exist"
msgstr "Streams-enabled-Verzeichnis existiert nicht"
#: src/views/nginx_log/NginxLog.vue:55
#: src/views/nginx_log/NginxLog.vue:77
msgid "Structured"
msgstr "Strukturiert"
@@ -7322,7 +7322,7 @@ msgstr "Schreibe Zertifikat auf die Festplatte"
msgid "Yes"
msgstr "Ja"
#: src/views/terminal/Terminal.vue:201
#: src/views/terminal/Terminal.vue:200
msgid ""
"You are accessing this terminal over an insecure HTTP connection on a non-"
"localhost domain. This may expose sensitive information."
+9 -9
View File
@@ -461,7 +461,7 @@ msgstr ""
msgid "Auto Backup Storage Failed"
msgstr ""
#: src/views/nginx_log/NginxLog.vue:64 src/views/node/Node.vue:164
#: src/views/nginx_log/NginxLog.vue:86 src/views/node/Node.vue:164
msgid "Auto Refresh"
msgstr ""
@@ -513,7 +513,7 @@ msgstr ""
#: src/views/certificate/components/CertificateActions.vue:22
#: src/views/config/components/ConfigLeftPanel.vue:273
#: src/views/config/ConfigList.vue:120 src/views/config/ConfigList.vue:217
#: src/views/nginx_log/NginxLog.vue:92
#: src/views/nginx_log/NginxLog.vue:114
#: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:170
#: src/views/stream/components/StreamEditor.vue:134
msgid "Back"
@@ -1450,7 +1450,7 @@ msgstr ""
#: src/routes/modules/dashboard.ts:10
#: src/views/config/components/ConfigLeftPanel.vue:109
#: src/views/config/components/ConfigLeftPanel.vue:159
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:56
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:78
msgid "Dashboard"
msgstr ""
@@ -2661,11 +2661,11 @@ msgstr ""
msgid "Filename is empty"
msgstr ""
#: src/views/nginx_log/raw/RawLogViewer.vue:155
#: src/views/nginx_log/raw/RawLogViewer.vue:298
msgid "Filter"
msgstr ""
#: src/views/nginx_log/raw/RawLogViewer.vue:158
#: src/views/nginx_log/raw/RawLogViewer.vue:301
msgid "Filter log content"
msgstr ""
@@ -3954,7 +3954,7 @@ msgstr ""
msgid "Nginx is running"
msgstr ""
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:39
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:61
msgid "Nginx Log"
msgstr ""
@@ -4832,7 +4832,7 @@ msgstr ""
msgid "Quick Select"
msgstr ""
#: src/views/nginx_log/NginxLog.vue:57
#: src/views/nginx_log/NginxLog.vue:79
msgid "Raw"
msgstr ""
@@ -5929,7 +5929,7 @@ msgstr ""
msgid "Streams-enabled directory not exist"
msgstr ""
#: src/views/nginx_log/NginxLog.vue:55
#: src/views/nginx_log/NginxLog.vue:77
msgid "Structured"
msgstr ""
@@ -6960,7 +6960,7 @@ msgstr ""
msgid "Yes"
msgstr ""
#: src/views/terminal/Terminal.vue:201
#: src/views/terminal/Terminal.vue:200
msgid ""
"You are accessing this terminal over an insecure HTTP connection on a non-"
"localhost domain. This may expose sensitive information."
+9 -9
View File
@@ -501,7 +501,7 @@ msgstr "Copia de seguridad automática fallida"
msgid "Auto Backup Storage Failed"
msgstr "Fallo en el almacenamiento de copia de seguridad automática"
#: src/views/nginx_log/NginxLog.vue:64 src/views/node/Node.vue:164
#: src/views/nginx_log/NginxLog.vue:86 src/views/node/Node.vue:164
msgid "Auto Refresh"
msgstr "Actualización automática"
@@ -553,7 +553,7 @@ msgstr "Prom./PV"
#: src/views/certificate/components/CertificateActions.vue:22
#: src/views/config/components/ConfigLeftPanel.vue:273
#: src/views/config/ConfigList.vue:120 src/views/config/ConfigList.vue:217
#: src/views/nginx_log/NginxLog.vue:92
#: src/views/nginx_log/NginxLog.vue:114
#: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:170
#: src/views/stream/components/StreamEditor.vue:134
msgid "Back"
@@ -1555,7 +1555,7 @@ msgstr "Diariamente a las %{time}"
#: src/routes/modules/dashboard.ts:10
#: src/views/config/components/ConfigLeftPanel.vue:109
#: src/views/config/components/ConfigLeftPanel.vue:159
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:56
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:78
msgid "Dashboard"
msgstr "Panel"
@@ -2788,11 +2788,11 @@ msgstr "Archivo subido correctamente"
msgid "Filename is empty"
msgstr "El nombre del archivo está vacío"
#: src/views/nginx_log/raw/RawLogViewer.vue:155
#: src/views/nginx_log/raw/RawLogViewer.vue:298
msgid "Filter"
msgstr "Filtro"
#: src/views/nginx_log/raw/RawLogViewer.vue:158
#: src/views/nginx_log/raw/RawLogViewer.vue:301
msgid "Filter log content"
msgstr "Filtrar contenido del registro"
@@ -4122,7 +4122,7 @@ msgstr "Nginx no se está ejecutando en otro contenedor"
msgid "Nginx is running"
msgstr "Nginx está en ejecución"
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:39
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:61
msgid "Nginx Log"
msgstr "Registro Nginx"
@@ -5045,7 +5045,7 @@ msgstr "En cola para indexación..."
msgid "Quick Select"
msgstr "Selección rápida"
#: src/views/nginx_log/NginxLog.vue:57
#: src/views/nginx_log/NginxLog.vue:79
msgid "Raw"
msgstr "Crudo"
@@ -6176,7 +6176,7 @@ msgstr "El directorio streams-available no existe"
msgid "Streams-enabled directory not exist"
msgstr "El directorio streams-enabled no existe"
#: src/views/nginx_log/NginxLog.vue:55
#: src/views/nginx_log/NginxLog.vue:77
msgid "Structured"
msgstr "Estructurado"
@@ -7300,7 +7300,7 @@ msgstr "Escribir certificado a disco"
msgid "Yes"
msgstr "Si"
#: src/views/terminal/Terminal.vue:201
#: src/views/terminal/Terminal.vue:200
msgid ""
"You are accessing this terminal over an insecure HTTP connection on a non-"
"localhost domain. This may expose sensitive information."
+9 -9
View File
@@ -503,7 +503,7 @@ msgstr "Échec de la sauvegarde automatique"
msgid "Auto Backup Storage Failed"
msgstr "Échec du stockage de sauvegarde automatique"
#: src/views/nginx_log/NginxLog.vue:64 src/views/node/Node.vue:164
#: src/views/nginx_log/NginxLog.vue:86 src/views/node/Node.vue:164
msgid "Auto Refresh"
msgstr "Actualisation automatique"
@@ -555,7 +555,7 @@ msgstr "Moy./PV"
#: src/views/certificate/components/CertificateActions.vue:22
#: src/views/config/components/ConfigLeftPanel.vue:273
#: src/views/config/ConfigList.vue:120 src/views/config/ConfigList.vue:217
#: src/views/nginx_log/NginxLog.vue:92
#: src/views/nginx_log/NginxLog.vue:114
#: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:170
#: src/views/stream/components/StreamEditor.vue:134
msgid "Back"
@@ -1561,7 +1561,7 @@ msgstr "Quotidiennement à %{time}"
#: src/routes/modules/dashboard.ts:10
#: src/views/config/components/ConfigLeftPanel.vue:109
#: src/views/config/components/ConfigLeftPanel.vue:159
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:56
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:78
msgid "Dashboard"
msgstr "Dashboard"
@@ -2794,11 +2794,11 @@ msgstr "Fichier téléchargé avec succès"
msgid "Filename is empty"
msgstr "Nom du fichier vide"
#: src/views/nginx_log/raw/RawLogViewer.vue:155
#: src/views/nginx_log/raw/RawLogViewer.vue:298
msgid "Filter"
msgstr "Filtrer"
#: src/views/nginx_log/raw/RawLogViewer.vue:158
#: src/views/nginx_log/raw/RawLogViewer.vue:301
msgid "Filter log content"
msgstr "Filtrer le contenu du journal"
@@ -4132,7 +4132,7 @@ msgstr "Nginx ne fonctionne pas dans un autre conteneur"
msgid "Nginx is running"
msgstr "Nginx est en cours d'exécution"
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:39
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:61
msgid "Nginx Log"
msgstr "Journal Nginx"
@@ -5055,7 +5055,7 @@ msgstr "En attente d'indexation..."
msgid "Quick Select"
msgstr "Sélection rapide"
#: src/views/nginx_log/NginxLog.vue:57
#: src/views/nginx_log/NginxLog.vue:79
msgid "Raw"
msgstr "Brut"
@@ -6186,7 +6186,7 @@ msgstr "Le répertoire streams-available n'existe pas"
msgid "Streams-enabled directory not exist"
msgstr "Le répertoire streams-enabled n'existe pas"
#: src/views/nginx_log/NginxLog.vue:55
#: src/views/nginx_log/NginxLog.vue:77
msgid "Structured"
msgstr "Structuré"
@@ -7325,7 +7325,7 @@ msgstr "Écriture du certificat sur le disque"
msgid "Yes"
msgstr "Oui"
#: src/views/terminal/Terminal.vue:201
#: src/views/terminal/Terminal.vue:200
msgid ""
"You are accessing this terminal over an insecure HTTP connection on a non-"
"localhost domain. This may expose sensitive information."
+9 -9
View File
@@ -489,7 +489,7 @@ msgstr "自動バックアップが失敗しました"
msgid "Auto Backup Storage Failed"
msgstr "自動バックアップの保存に失敗しました"
#: src/views/nginx_log/NginxLog.vue:64 src/views/node/Node.vue:164
#: src/views/nginx_log/NginxLog.vue:86 src/views/node/Node.vue:164
msgid "Auto Refresh"
msgstr "自動更新"
@@ -541,7 +541,7 @@ msgstr "平均/PV"
#: src/views/certificate/components/CertificateActions.vue:22
#: src/views/config/components/ConfigLeftPanel.vue:273
#: src/views/config/ConfigList.vue:120 src/views/config/ConfigList.vue:217
#: src/views/nginx_log/NginxLog.vue:92
#: src/views/nginx_log/NginxLog.vue:114
#: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:170
#: src/views/stream/components/StreamEditor.vue:134
msgid "Back"
@@ -1526,7 +1526,7 @@ msgstr "毎日 %{time}"
#: src/routes/modules/dashboard.ts:10
#: src/views/config/components/ConfigLeftPanel.vue:109
#: src/views/config/components/ConfigLeftPanel.vue:159
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:56
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:78
msgid "Dashboard"
msgstr "ダッシュボード"
@@ -2750,11 +2750,11 @@ msgstr "ファイルが正常にアップロードされました"
msgid "Filename is empty"
msgstr "ファイル名が空です"
#: src/views/nginx_log/raw/RawLogViewer.vue:155
#: src/views/nginx_log/raw/RawLogViewer.vue:298
msgid "Filter"
msgstr "フィルター"
#: src/views/nginx_log/raw/RawLogViewer.vue:158
#: src/views/nginx_log/raw/RawLogViewer.vue:301
msgid "Filter log content"
msgstr "ログ内容をフィルタリング"
@@ -4080,7 +4080,7 @@ msgstr "Nginx は他のコンテナで実行されていません"
msgid "Nginx is running"
msgstr "Nginx は実行中です"
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:39
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:61
msgid "Nginx Log"
msgstr "Nginx ログ"
@@ -4980,7 +4980,7 @@ msgstr "インデックス作成待ち..."
msgid "Quick Select"
msgstr "クイック選択"
#: src/views/nginx_log/NginxLog.vue:57
#: src/views/nginx_log/NginxLog.vue:79
msgid "Raw"
msgstr "生"
@@ -6101,7 +6101,7 @@ msgstr "streams-available ディレクトリが存在しません"
msgid "Streams-enabled directory not exist"
msgstr "streams-enabled ディレクトリが存在しません"
#: src/views/nginx_log/NginxLog.vue:55
#: src/views/nginx_log/NginxLog.vue:77
msgid "Structured"
msgstr "構造化"
@@ -7213,7 +7213,7 @@ msgstr "証明書をディスクに書き込み中"
msgid "Yes"
msgstr "はい"
#: src/views/terminal/Terminal.vue:201
#: src/views/terminal/Terminal.vue:200
msgid ""
"You are accessing this terminal over an insecure HTTP connection on a non-"
"localhost domain. This may expose sensitive information."
+9 -9
View File
@@ -483,7 +483,7 @@ msgstr "자동 백업 실패"
msgid "Auto Backup Storage Failed"
msgstr "자동 백업 저장 실패"
#: src/views/nginx_log/NginxLog.vue:64 src/views/node/Node.vue:164
#: src/views/nginx_log/NginxLog.vue:86 src/views/node/Node.vue:164
msgid "Auto Refresh"
msgstr "자동 새로고침"
@@ -535,7 +535,7 @@ msgstr "평균/PV"
#: src/views/certificate/components/CertificateActions.vue:22
#: src/views/config/components/ConfigLeftPanel.vue:273
#: src/views/config/ConfigList.vue:120 src/views/config/ConfigList.vue:217
#: src/views/nginx_log/NginxLog.vue:92
#: src/views/nginx_log/NginxLog.vue:114
#: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:170
#: src/views/stream/components/StreamEditor.vue:134
msgid "Back"
@@ -1506,7 +1506,7 @@ msgstr "매일 %{time}"
#: src/routes/modules/dashboard.ts:10
#: src/views/config/components/ConfigLeftPanel.vue:109
#: src/views/config/components/ConfigLeftPanel.vue:159
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:56
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:78
msgid "Dashboard"
msgstr "대시보드"
@@ -2726,11 +2726,11 @@ msgstr "파일이 성공적으로 업로드되었습니다"
msgid "Filename is empty"
msgstr "파일 이름이 비어 있습니다"
#: src/views/nginx_log/raw/RawLogViewer.vue:155
#: src/views/nginx_log/raw/RawLogViewer.vue:298
msgid "Filter"
msgstr "필터"
#: src/views/nginx_log/raw/RawLogViewer.vue:158
#: src/views/nginx_log/raw/RawLogViewer.vue:301
msgid "Filter log content"
msgstr "로그 내용 필터링"
@@ -4045,7 +4045,7 @@ msgstr "Nginx가 다른 컨테이너에서 실행되고 있지 않습니다"
msgid "Nginx is running"
msgstr "Nginx가 실행 중입니다"
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:39
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:61
msgid "Nginx Log"
msgstr "Nginx 로그"
@@ -4938,7 +4938,7 @@ msgstr "인덱싱 대기 중..."
msgid "Quick Select"
msgstr "빠른 선택"
#: src/views/nginx_log/NginxLog.vue:57
#: src/views/nginx_log/NginxLog.vue:79
msgid "Raw"
msgstr "원시"
@@ -6058,7 +6058,7 @@ msgstr "streams-available 디렉터리가 존재하지 않습니다"
msgid "Streams-enabled directory not exist"
msgstr "streams-enabled 디렉터리가 존재하지 않습니다"
#: src/views/nginx_log/NginxLog.vue:55
#: src/views/nginx_log/NginxLog.vue:77
msgid "Structured"
msgstr "구조화된"
@@ -7160,7 +7160,7 @@ msgstr "인증서를 디스크에 쓰기"
msgid "Yes"
msgstr "예"
#: src/views/terminal/Terminal.vue:201
#: src/views/terminal/Terminal.vue:200
msgid ""
"You are accessing this terminal over an insecure HTTP connection on a non-"
"localhost domain. This may expose sensitive information."
+9 -9
View File
@@ -468,7 +468,7 @@ msgstr ""
msgid "Auto Backup Storage Failed"
msgstr ""
#: src/views/nginx_log/NginxLog.vue:64
#: src/views/nginx_log/NginxLog.vue:86
#: src/views/node/Node.vue:164
msgid "Auto Refresh"
msgstr ""
@@ -522,7 +522,7 @@ msgstr ""
#: src/views/config/components/ConfigLeftPanel.vue:273
#: src/views/config/ConfigList.vue:120
#: src/views/config/ConfigList.vue:217
#: src/views/nginx_log/NginxLog.vue:92
#: src/views/nginx_log/NginxLog.vue:114
#: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:170
#: src/views/stream/components/StreamEditor.vue:134
msgid "Back"
@@ -1423,7 +1423,7 @@ msgstr ""
#: src/views/config/components/ConfigLeftPanel.vue:109
#: src/views/config/components/ConfigLeftPanel.vue:159
#: src/views/config/ConfigList.vue:69
#: src/views/nginx_log/NginxLog.vue:56
#: src/views/nginx_log/NginxLog.vue:78
msgid "Dashboard"
msgstr ""
@@ -2634,11 +2634,11 @@ msgstr ""
msgid "Filename is empty"
msgstr ""
#: src/views/nginx_log/raw/RawLogViewer.vue:155
#: src/views/nginx_log/raw/RawLogViewer.vue:298
msgid "Filter"
msgstr ""
#: src/views/nginx_log/raw/RawLogViewer.vue:158
#: src/views/nginx_log/raw/RawLogViewer.vue:301
msgid "Filter log content"
msgstr ""
@@ -3914,7 +3914,7 @@ msgid "Nginx is running"
msgstr ""
#: src/routes/modules/nginx_log.ts:9
#: src/views/nginx_log/NginxLog.vue:39
#: src/views/nginx_log/NginxLog.vue:61
msgid "Nginx Log"
msgstr ""
@@ -4781,7 +4781,7 @@ msgstr ""
msgid "Quick Select"
msgstr ""
#: src/views/nginx_log/NginxLog.vue:57
#: src/views/nginx_log/NginxLog.vue:79
msgid "Raw"
msgstr ""
@@ -5873,7 +5873,7 @@ msgstr ""
msgid "Streams-enabled directory not exist"
msgstr ""
#: src/views/nginx_log/NginxLog.vue:55
#: src/views/nginx_log/NginxLog.vue:77
msgid "Structured"
msgstr ""
@@ -6852,7 +6852,7 @@ msgstr ""
msgid "Yes"
msgstr ""
#: src/views/terminal/Terminal.vue:201
#: src/views/terminal/Terminal.vue:200
msgid "You are accessing this terminal over an insecure HTTP connection on a non-localhost domain. This may expose sensitive information."
msgstr ""
+9 -9
View File
@@ -495,7 +495,7 @@ msgstr "Backup automático falhou"
msgid "Auto Backup Storage Failed"
msgstr "Falha no armazenamento de backup automático"
#: src/views/nginx_log/NginxLog.vue:64 src/views/node/Node.vue:164
#: src/views/nginx_log/NginxLog.vue:86 src/views/node/Node.vue:164
msgid "Auto Refresh"
msgstr "Actualizar Automaticamente"
@@ -547,7 +547,7 @@ msgstr "Méd./PV"
#: src/views/certificate/components/CertificateActions.vue:22
#: src/views/config/components/ConfigLeftPanel.vue:273
#: src/views/config/ConfigList.vue:120 src/views/config/ConfigList.vue:217
#: src/views/nginx_log/NginxLog.vue:92
#: src/views/nginx_log/NginxLog.vue:114
#: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:170
#: src/views/stream/components/StreamEditor.vue:134
msgid "Back"
@@ -1543,7 +1543,7 @@ msgstr "Diariamente às %{time}"
#: src/routes/modules/dashboard.ts:10
#: src/views/config/components/ConfigLeftPanel.vue:109
#: src/views/config/components/ConfigLeftPanel.vue:159
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:56
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:78
msgid "Dashboard"
msgstr "Painel"
@@ -2769,11 +2769,11 @@ msgstr "Ficheiro carregado com sucesso"
msgid "Filename is empty"
msgstr "O nome do ficheiro está vazio"
#: src/views/nginx_log/raw/RawLogViewer.vue:155
#: src/views/nginx_log/raw/RawLogViewer.vue:298
msgid "Filter"
msgstr "Filtro"
#: src/views/nginx_log/raw/RawLogViewer.vue:158
#: src/views/nginx_log/raw/RawLogViewer.vue:301
msgid "Filter log content"
msgstr "Filtrar conteúdo do registo"
@@ -4103,7 +4103,7 @@ msgstr "O Nginx não está em execução noutro contentor"
msgid "Nginx is running"
msgstr "O Nginx está em execução"
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:39
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:61
msgid "Nginx Log"
msgstr "Logs do Nginx"
@@ -5022,7 +5022,7 @@ msgstr "Na fila para indexação..."
msgid "Quick Select"
msgstr "Seleção rápida"
#: src/views/nginx_log/NginxLog.vue:57
#: src/views/nginx_log/NginxLog.vue:79
msgid "Raw"
msgstr "Bruto"
@@ -6149,7 +6149,7 @@ msgstr "O diretório streams-available não existe"
msgid "Streams-enabled directory not exist"
msgstr "O diretório streams-enabled não existe"
#: src/views/nginx_log/NginxLog.vue:55
#: src/views/nginx_log/NginxLog.vue:77
msgid "Structured"
msgstr "Estruturado"
@@ -7273,7 +7273,7 @@ msgstr "Escrevendo certificado no disco"
msgid "Yes"
msgstr "Sim"
#: src/views/terminal/Terminal.vue:201
#: src/views/terminal/Terminal.vue:200
msgid ""
"You are accessing this terminal over an insecure HTTP connection on a non-"
"localhost domain. This may expose sensitive information."
+9 -9
View File
@@ -496,7 +496,7 @@ msgstr "Автоматическое резервное копирование
msgid "Auto Backup Storage Failed"
msgstr "Сбой хранения автоматической резервной копии"
#: src/views/nginx_log/NginxLog.vue:64 src/views/node/Node.vue:164
#: src/views/nginx_log/NginxLog.vue:86 src/views/node/Node.vue:164
msgid "Auto Refresh"
msgstr "Автообновление"
@@ -548,7 +548,7 @@ msgstr "Сред./PV"
#: src/views/certificate/components/CertificateActions.vue:22
#: src/views/config/components/ConfigLeftPanel.vue:273
#: src/views/config/ConfigList.vue:120 src/views/config/ConfigList.vue:217
#: src/views/nginx_log/NginxLog.vue:92
#: src/views/nginx_log/NginxLog.vue:114
#: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:170
#: src/views/stream/components/StreamEditor.vue:134
msgid "Back"
@@ -1543,7 +1543,7 @@ msgstr "Ежедневно в %{time}"
#: src/routes/modules/dashboard.ts:10
#: src/views/config/components/ConfigLeftPanel.vue:109
#: src/views/config/components/ConfigLeftPanel.vue:159
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:56
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:78
msgid "Dashboard"
msgstr "Доска"
@@ -2770,11 +2770,11 @@ msgstr "Файл успешно загружен"
msgid "Filename is empty"
msgstr "Имя файла пустое"
#: src/views/nginx_log/raw/RawLogViewer.vue:155
#: src/views/nginx_log/raw/RawLogViewer.vue:298
msgid "Filter"
msgstr "Фильтр"
#: src/views/nginx_log/raw/RawLogViewer.vue:158
#: src/views/nginx_log/raw/RawLogViewer.vue:301
msgid "Filter log content"
msgstr "Фильтровать содержимое журнала"
@@ -4101,7 +4101,7 @@ msgstr "Nginx не работает в другом контейнере"
msgid "Nginx is running"
msgstr "Nginx работает"
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:39
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:61
msgid "Nginx Log"
msgstr "Журнал"
@@ -5021,7 +5021,7 @@ msgstr "В очереди на индексацию..."
msgid "Quick Select"
msgstr "Быстрый выбор"
#: src/views/nginx_log/NginxLog.vue:57
#: src/views/nginx_log/NginxLog.vue:79
msgid "Raw"
msgstr "Сырой"
@@ -6144,7 +6144,7 @@ msgstr "Каталог streams-available не существует"
msgid "Streams-enabled directory not exist"
msgstr "Каталог streams-enabled не существует"
#: src/views/nginx_log/NginxLog.vue:55
#: src/views/nginx_log/NginxLog.vue:77
msgid "Structured"
msgstr "Структурированный"
@@ -7260,7 +7260,7 @@ msgstr "Запись сертификата на диск"
msgid "Yes"
msgstr "Да"
#: src/views/terminal/Terminal.vue:201
#: src/views/terminal/Terminal.vue:200
msgid ""
"You are accessing this terminal over an insecure HTTP connection on a non-"
"localhost domain. This may expose sensitive information."
+9 -9
View File
@@ -498,7 +498,7 @@ msgstr "Otomatik Yedekleme Başarısız"
msgid "Auto Backup Storage Failed"
msgstr "Otomatik Yedekleme Depolama Başarısız"
#: src/views/nginx_log/NginxLog.vue:64 src/views/node/Node.vue:164
#: src/views/nginx_log/NginxLog.vue:86 src/views/node/Node.vue:164
msgid "Auto Refresh"
msgstr "Otomatik Yenileme"
@@ -550,7 +550,7 @@ msgstr "Ort./PV"
#: src/views/certificate/components/CertificateActions.vue:22
#: src/views/config/components/ConfigLeftPanel.vue:273
#: src/views/config/ConfigList.vue:120 src/views/config/ConfigList.vue:217
#: src/views/nginx_log/NginxLog.vue:92
#: src/views/nginx_log/NginxLog.vue:114
#: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:170
#: src/views/stream/components/StreamEditor.vue:134
msgid "Back"
@@ -1541,7 +1541,7 @@ msgstr "Günlük olarak saat %{time}"
#: src/routes/modules/dashboard.ts:10
#: src/views/config/components/ConfigLeftPanel.vue:109
#: src/views/config/components/ConfigLeftPanel.vue:159
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:56
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:78
msgid "Dashboard"
msgstr "Kontrol Paneli"
@@ -2770,11 +2770,11 @@ msgstr "Dosya başarıyla yüklendi"
msgid "Filename is empty"
msgstr "Dosya adı boş"
#: src/views/nginx_log/raw/RawLogViewer.vue:155
#: src/views/nginx_log/raw/RawLogViewer.vue:298
msgid "Filter"
msgstr "Filtre"
#: src/views/nginx_log/raw/RawLogViewer.vue:158
#: src/views/nginx_log/raw/RawLogViewer.vue:301
msgid "Filter log content"
msgstr "Günlük içeriğini filtrele"
@@ -4103,7 +4103,7 @@ msgstr "Nginx başka bir konteynerde çalışmıyor"
msgid "Nginx is running"
msgstr "Nginx çalışıyor"
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:39
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:61
msgid "Nginx Log"
msgstr "Nginx Günlüğü"
@@ -5015,7 +5015,7 @@ msgstr "Dizine ekleme için sırada..."
msgid "Quick Select"
msgstr "Hızlı Seçim"
#: src/views/nginx_log/NginxLog.vue:57
#: src/views/nginx_log/NginxLog.vue:79
msgid "Raw"
msgstr "Ham"
@@ -6147,7 +6147,7 @@ msgstr "Streams-available dizini mevcut değil"
msgid "Streams-enabled directory not exist"
msgstr "Streams-enabled dizini mevcut değil"
#: src/views/nginx_log/NginxLog.vue:55
#: src/views/nginx_log/NginxLog.vue:77
msgid "Structured"
msgstr "Yapılandırılmış"
@@ -7265,7 +7265,7 @@ msgstr "Sertifika diske yazılıyor"
msgid "Yes"
msgstr "Evet"
#: src/views/terminal/Terminal.vue:201
#: src/views/terminal/Terminal.vue:200
msgid ""
"You are accessing this terminal over an insecure HTTP connection on a non-"
"localhost domain. This may expose sensitive information."
+9 -9
View File
@@ -497,7 +497,7 @@ msgstr "Автоматичне резервне копіювання не вда
msgid "Auto Backup Storage Failed"
msgstr "Не вдалося зберегти автоматичну резервну копію"
#: src/views/nginx_log/NginxLog.vue:64 src/views/node/Node.vue:164
#: src/views/nginx_log/NginxLog.vue:86 src/views/node/Node.vue:164
msgid "Auto Refresh"
msgstr "Автоматичне оновлення"
@@ -549,7 +549,7 @@ msgstr "Середн./PV"
#: src/views/certificate/components/CertificateActions.vue:22
#: src/views/config/components/ConfigLeftPanel.vue:273
#: src/views/config/ConfigList.vue:120 src/views/config/ConfigList.vue:217
#: src/views/nginx_log/NginxLog.vue:92
#: src/views/nginx_log/NginxLog.vue:114
#: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:170
#: src/views/stream/components/StreamEditor.vue:134
msgid "Back"
@@ -1579,7 +1579,7 @@ msgstr "Щодня о %{time}"
#: src/routes/modules/dashboard.ts:10
#: src/views/config/components/ConfigLeftPanel.vue:109
#: src/views/config/components/ConfigLeftPanel.vue:159
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:56
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:78
msgid "Dashboard"
msgstr "Панель керування"
@@ -2842,11 +2842,11 @@ msgstr "Файл успішно завантажено"
msgid "Filename is empty"
msgstr "Назва файлу порожня"
#: src/views/nginx_log/raw/RawLogViewer.vue:155
#: src/views/nginx_log/raw/RawLogViewer.vue:298
msgid "Filter"
msgstr "Фільтр"
#: src/views/nginx_log/raw/RawLogViewer.vue:158
#: src/views/nginx_log/raw/RawLogViewer.vue:301
msgid "Filter log content"
msgstr "Фільтрувати вміст журналу"
@@ -4172,7 +4172,7 @@ msgstr "Nginx не працює в іншому контейнері"
msgid "Nginx is running"
msgstr "Nginx працює"
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:39
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:61
msgid "Nginx Log"
msgstr "Nginx Журнал"
@@ -5088,7 +5088,7 @@ msgstr "У черзі на індексацію..."
msgid "Quick Select"
msgstr "Швидкий вибір"
#: src/views/nginx_log/NginxLog.vue:57
#: src/views/nginx_log/NginxLog.vue:79
msgid "Raw"
msgstr "Сирий"
@@ -6216,7 +6216,7 @@ msgstr "Каталог Streams-available не існує"
msgid "Streams-enabled directory not exist"
msgstr "Каталог streams-enabled не існує"
#: src/views/nginx_log/NginxLog.vue:55
#: src/views/nginx_log/NginxLog.vue:77
msgid "Structured"
msgstr "Структурований"
@@ -7330,7 +7330,7 @@ msgstr "Запис сертифіката на диск"
msgid "Yes"
msgstr "Так"
#: src/views/terminal/Terminal.vue:201
#: src/views/terminal/Terminal.vue:200
msgid ""
"You are accessing this terminal over an insecure HTTP connection on a non-"
"localhost domain. This may expose sensitive information."
+9 -9
View File
@@ -484,7 +484,7 @@ msgstr "Sao lưu tự động thất bại"
msgid "Auto Backup Storage Failed"
msgstr "Lưu trữ sao lưu tự động thất bại"
#: src/views/nginx_log/NginxLog.vue:64 src/views/node/Node.vue:164
#: src/views/nginx_log/NginxLog.vue:86 src/views/node/Node.vue:164
msgid "Auto Refresh"
msgstr "Tự động làm mới"
@@ -536,7 +536,7 @@ msgstr "TB/PV"
#: src/views/certificate/components/CertificateActions.vue:22
#: src/views/config/components/ConfigLeftPanel.vue:273
#: src/views/config/ConfigList.vue:120 src/views/config/ConfigList.vue:217
#: src/views/nginx_log/NginxLog.vue:92
#: src/views/nginx_log/NginxLog.vue:114
#: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:170
#: src/views/stream/components/StreamEditor.vue:134
msgid "Back"
@@ -1517,7 +1517,7 @@ msgstr "Hàng ngày lúc %{time}"
#: src/routes/modules/dashboard.ts:10
#: src/views/config/components/ConfigLeftPanel.vue:109
#: src/views/config/components/ConfigLeftPanel.vue:159
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:56
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:78
msgid "Dashboard"
msgstr "Bảng điều khiển"
@@ -2741,11 +2741,11 @@ msgstr "Tải lên tệp thành công"
msgid "Filename is empty"
msgstr "Tên tệp trống"
#: src/views/nginx_log/raw/RawLogViewer.vue:155
#: src/views/nginx_log/raw/RawLogViewer.vue:298
msgid "Filter"
msgstr "Lọc"
#: src/views/nginx_log/raw/RawLogViewer.vue:158
#: src/views/nginx_log/raw/RawLogViewer.vue:301
msgid "Filter log content"
msgstr "Lọc nội dung nhật ký"
@@ -4068,7 +4068,7 @@ msgstr "Nginx không chạy trong một container khác"
msgid "Nginx is running"
msgstr "Nginx đang chạy"
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:39
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:61
msgid "Nginx Log"
msgstr "Nhật ký Nginx"
@@ -4971,7 +4971,7 @@ msgstr "Đang xếp hàng để lập chỉ mục..."
msgid "Quick Select"
msgstr "Chọn nhanh"
#: src/views/nginx_log/NginxLog.vue:57
#: src/views/nginx_log/NginxLog.vue:79
msgid "Raw"
msgstr "Thô"
@@ -6091,7 +6091,7 @@ msgstr "Thư mục Streams-available không tồn tại"
msgid "Streams-enabled directory not exist"
msgstr "Thư mục streams-enabled không tồn tại"
#: src/views/nginx_log/NginxLog.vue:55
#: src/views/nginx_log/NginxLog.vue:77
msgid "Structured"
msgstr "Có cấu trúc"
@@ -7202,7 +7202,7 @@ msgstr "Ghi chứng chỉ vào disk"
msgid "Yes"
msgstr "Có"
#: src/views/terminal/Terminal.vue:201
#: src/views/terminal/Terminal.vue:200
msgid ""
"You are accessing this terminal over an insecure HTTP connection on a non-"
"localhost domain. This may expose sensitive information."
+9 -9
View File
@@ -480,7 +480,7 @@ msgstr "自动备份失败"
msgid "Auto Backup Storage Failed"
msgstr "自动备份存储失败"
#: src/views/nginx_log/NginxLog.vue:64 src/views/node/Node.vue:164
#: src/views/nginx_log/NginxLog.vue:86 src/views/node/Node.vue:164
msgid "Auto Refresh"
msgstr "自动刷新"
@@ -532,7 +532,7 @@ msgstr "平均/PV"
#: src/views/certificate/components/CertificateActions.vue:22
#: src/views/config/components/ConfigLeftPanel.vue:273
#: src/views/config/ConfigList.vue:120 src/views/config/ConfigList.vue:217
#: src/views/nginx_log/NginxLog.vue:92
#: src/views/nginx_log/NginxLog.vue:114
#: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:170
#: src/views/stream/components/StreamEditor.vue:134
msgid "Back"
@@ -1492,7 +1492,7 @@ msgstr "每天 %{time}"
#: src/routes/modules/dashboard.ts:10
#: src/views/config/components/ConfigLeftPanel.vue:109
#: src/views/config/components/ConfigLeftPanel.vue:159
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:56
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:78
msgid "Dashboard"
msgstr "仪表盘"
@@ -2707,11 +2707,11 @@ msgstr "文件上传成功"
msgid "Filename is empty"
msgstr "文件名为空"
#: src/views/nginx_log/raw/RawLogViewer.vue:155
#: src/views/nginx_log/raw/RawLogViewer.vue:298
msgid "Filter"
msgstr "过滤"
#: src/views/nginx_log/raw/RawLogViewer.vue:158
#: src/views/nginx_log/raw/RawLogViewer.vue:301
msgid "Filter log content"
msgstr "过滤日志内容"
@@ -4016,7 +4016,7 @@ msgstr "Nginx 未在另一个容器中运行"
msgid "Nginx is running"
msgstr "Nginx 正在运行"
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:39
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:61
msgid "Nginx Log"
msgstr "Nginx 日志"
@@ -4903,7 +4903,7 @@ msgstr "排队等待索引中..."
msgid "Quick Select"
msgstr "快速选择"
#: src/views/nginx_log/NginxLog.vue:57
#: src/views/nginx_log/NginxLog.vue:79
msgid "Raw"
msgstr "原始"
@@ -6008,7 +6008,7 @@ msgstr "Streams-available 目录不存在"
msgid "Streams-enabled directory not exist"
msgstr "Streams-enabled 目录不存在"
#: src/views/nginx_log/NginxLog.vue:55
#: src/views/nginx_log/NginxLog.vue:77
msgid "Structured"
msgstr "结构化"
@@ -7071,7 +7071,7 @@ msgstr "正在将证书写入磁盘"
msgid "Yes"
msgstr "是的"
#: src/views/terminal/Terminal.vue:201
#: src/views/terminal/Terminal.vue:200
msgid ""
"You are accessing this terminal over an insecure HTTP connection on a non-"
"localhost domain. This may expose sensitive information."
+9 -9
View File
@@ -484,7 +484,7 @@ msgstr "自動備份失敗"
msgid "Auto Backup Storage Failed"
msgstr "自動備份儲存失敗"
#: src/views/nginx_log/NginxLog.vue:64 src/views/node/Node.vue:164
#: src/views/nginx_log/NginxLog.vue:86 src/views/node/Node.vue:164
msgid "Auto Refresh"
msgstr "自動重新整理"
@@ -536,7 +536,7 @@ msgstr "平均 /PV"
#: src/views/certificate/components/CertificateActions.vue:22
#: src/views/config/components/ConfigLeftPanel.vue:273
#: src/views/config/ConfigList.vue:120 src/views/config/ConfigList.vue:217
#: src/views/nginx_log/NginxLog.vue:92
#: src/views/nginx_log/NginxLog.vue:114
#: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:170
#: src/views/stream/components/StreamEditor.vue:134
msgid "Back"
@@ -1497,7 +1497,7 @@ msgstr "每天 %{time}"
#: src/routes/modules/dashboard.ts:10
#: src/views/config/components/ConfigLeftPanel.vue:109
#: src/views/config/components/ConfigLeftPanel.vue:159
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:56
#: src/views/config/ConfigList.vue:69 src/views/nginx_log/NginxLog.vue:78
msgid "Dashboard"
msgstr "儀錶板"
@@ -2712,11 +2712,11 @@ msgstr "檔案上傳成功"
msgid "Filename is empty"
msgstr "檔名空白"
#: src/views/nginx_log/raw/RawLogViewer.vue:155
#: src/views/nginx_log/raw/RawLogViewer.vue:298
msgid "Filter"
msgstr "篩選"
#: src/views/nginx_log/raw/RawLogViewer.vue:158
#: src/views/nginx_log/raw/RawLogViewer.vue:301
msgid "Filter log content"
msgstr "過濾日誌內容"
@@ -4020,7 +4020,7 @@ msgstr "Nginx 未在另一個容器中運行"
msgid "Nginx is running"
msgstr "Nginx 執行中"
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:39
#: src/routes/modules/nginx_log.ts:9 src/views/nginx_log/NginxLog.vue:61
msgid "Nginx Log"
msgstr "Nginx 日誌"
@@ -4907,7 +4907,7 @@ msgstr "排隊等待索引中..."
msgid "Quick Select"
msgstr "快速選擇"
#: src/views/nginx_log/NginxLog.vue:57
#: src/views/nginx_log/NginxLog.vue:79
msgid "Raw"
msgstr "原始"
@@ -6011,7 +6011,7 @@ msgstr "streams-available 資料夾不存在"
msgid "Streams-enabled directory not exist"
msgstr "streams-enabled 資料夾不存在"
#: src/views/nginx_log/NginxLog.vue:55
#: src/views/nginx_log/NginxLog.vue:77
msgid "Structured"
msgstr "結構化"
@@ -7076,7 +7076,7 @@ msgstr "將憑證寫入磁碟"
msgid "Yes"
msgstr "是的"
#: src/views/terminal/Terminal.vue:201
#: src/views/terminal/Terminal.vue:200
msgid ""
"You are accessing this terminal over an insecure HTTP connection on a non-"
"localhost domain. This may expose sensitive information."
+15 -15
View File
@@ -133,19 +133,19 @@ func (s *Scanner) Initialize(ctx context.Context) error {
// Start background processes with WaitGroup tracking
s.wg.Go(func() {
logger.Info("Started cache watchForChanges goroutine")
logger.Debug("Started cache watchForChanges goroutine")
s.watchForChanges()
logger.Info("Cache watchForChanges goroutine completed")
})
s.wg.Go(func() {
logger.Info("Started cache periodicScan goroutine")
logger.Debug("Started cache periodicScan goroutine")
s.periodicScan()
logger.Info("Cache periodicScan goroutine completed")
})
s.wg.Go(func() {
logger.Info("Started cache handleShutdown goroutine")
logger.Debug("Started cache handleShutdown goroutine")
s.handleShutdown()
logger.Info("Cache handleShutdown goroutine completed")
})
@@ -153,9 +153,9 @@ func (s *Scanner) Initialize(ctx context.Context) error {
// Perform initial scan asynchronously to avoid blocking boot process
// Pass the context to ensure proper cancellation
s.wg.Go(func() {
logger.Info("Started cache initialScanAsync goroutine")
logger.Debug("Started cache initialScanAsync goroutine")
s.initialScanAsync(ctx)
logger.Info("Cache initialScanAsync goroutine completed")
logger.Debug("Cache initialScanAsync goroutine completed")
})
return nil
@@ -219,7 +219,7 @@ func (s *Scanner) periodicScan() {
// handleShutdown listens for context cancellation and shuts down gracefully
func (s *Scanner) handleShutdown() {
<-s.ctx.Done()
logger.Info("Shutting down Index Scanner")
logger.Debug("Shutting down Index Scanner")
// Note: Don't call s.Shutdown() here as it would cause deadlock
// Shutdown is called externally, this just handles cleanup
}
@@ -243,8 +243,8 @@ func (s *Scanner) initialScanAsync(ctx context.Context) {
default:
}
logger.Info("Starting initial config scan...")
logger.Infof("Config path: %s", nginx.GetConfPath())
logger.Debug("Starting initial config scan...")
logger.Debugf("Config path: %s", nginx.GetConfPath())
// Perform the scan with the fresh context (not scanner's internal context)
if err := s.scanAllConfigsWithContext(ctx); err != nil {
@@ -252,7 +252,7 @@ func (s *Scanner) initialScanAsync(ctx context.Context) {
if ctx.Err() == nil {
logger.Errorf("Initial config scan failed: %v", err)
} else {
logger.Infof("Initial config scan cancelled due to context: %v", ctx.Err())
logger.Debugf("Initial config scan cancelled due to context: %v", ctx.Err())
}
// Signal completion even on error so waiting services don't hang
initialScanOnce.Do(func() {
@@ -263,7 +263,7 @@ func (s *Scanner) initialScanAsync(ctx context.Context) {
// Signal that initial scan is complete - this allows other services to proceed
// that depend on the scan callbacks to have been processed
initialScanOnce.Do(func() {
logger.Info("Initial config scan and callbacks completed - signaling completion")
logger.Debug("Initial config scan and callbacks completed - signaling completion")
close(initialScanComplete)
})
}
@@ -275,14 +275,14 @@ func (s *Scanner) scanAllConfigsWithContext(ctx context.Context) error {
defer s.setScanningState(false)
root := nginx.GetConfPath()
logger.Infof("Scanning config directory: %s", root)
logger.Debugf("Scanning config directory: %s", root)
// Create a timeout context for the scan operation
scanCtx, scanCancel := context.WithTimeout(ctx, 15*time.Second)
defer scanCancel()
// Scan all files in the config directory and subdirectories
logger.Info("Starting filepath.WalkDir scanning...")
logger.Debug("Starting filepath.WalkDir scanning...")
// Use a channel to communicate scan results
type scanResult struct {
@@ -311,7 +311,7 @@ func (s *Scanner) scanAllConfigsWithContext(ctx context.Context) error {
// Wait for scan to complete or timeout
select {
case result := <-resultChan:
logger.Infof("Scan completed successfully: dirs=%d, files=%d, error=%v",
logger.Debugf("Scan completed successfully: dirs=%d, files=%d, error=%v",
result.dirCount, result.fileCount, result.err)
return result.err
case <-scanCtx.Done():
@@ -320,7 +320,7 @@ func (s *Scanner) scanAllConfigsWithContext(ctx context.Context) error {
// Wait a bit more for cleanup
select {
case result := <-resultChan:
logger.Infof("Scan completed after timeout: dirs=%d, files=%d, error=%v",
logger.Debugf("Scan completed after timeout: dirs=%d, files=%d, error=%v",
result.dirCount, result.fileCount, result.err)
return result.err
case <-time.After(2 * time.Second):
@@ -807,7 +807,7 @@ func WaitForInitialScanComplete() {
// Add timeout to prevent infinite waiting
select {
case <-initialScanComplete:
logger.Info("Initial config scan completion confirmed")
logger.Debug("Initial config scan completion confirmed")
case <-time.After(30 * time.Second):
logger.Warn("Timeout waiting for initial config scan completion - proceeding anyway")
}
+2 -2
View File
@@ -42,7 +42,7 @@ func (eb *Bus) SetWebSocketHub(hub WebSocketHub) {
eb.wsMutex.Lock()
defer eb.wsMutex.Unlock()
eb.wsHub = hub
logger.Info("WebSocket hub registered with event bus")
logger.Debug("WebSocket hub registered with event bus")
}
// Publish forwards an event directly to WebSocket clients
@@ -66,7 +66,7 @@ func (eb *Bus) Shutdown() {
defer eb.wsMutex.Unlock()
eb.wsHub = nil
logger.Info("Event bus shutdown completed")
logger.Debug("Event bus shutdown completed")
}
// Context returns the event bus context
+1 -1
View File
@@ -95,7 +95,7 @@ func (m *ProcessingStatusManager) BroadcastCurrentStatus() {
m.mu.RLock()
defer m.mu.RUnlock()
logger.Info("Broadcasting current processing status to new client")
logger.Debug("Broadcasting current processing status to new client")
Publish(Event{
Type: TypeProcessingStatus,
Data: m.status,
@@ -202,6 +202,10 @@ func (ao *AdaptiveOptimizer) cpuMonitoringLoop() {
// measureAndAdjustCPU measures current CPU utilization and suggests adjustments
func (ao *AdaptiveOptimizer) measureAndAdjustCPU() {
// Only adjust when indexer is actively processing
if !ao.isIndexerBusy() {
return
}
// Get current CPU utilization
cpuUsage := ao.getCurrentCPUUtilization()
@@ -258,6 +262,10 @@ func (ao *AdaptiveOptimizer) batchOptimizationLoop() {
// optimizeBatchSize analyzes performance and adjusts batch size
func (ao *AdaptiveOptimizer) optimizeBatchSize() {
// Only adjust when indexer is actively processing
if !ao.isIndexerBusy() {
return
}
ao.performanceHistory.mutex.RLock()
if len(ao.performanceHistory.samples) < 5 {
ao.performanceHistory.mutex.RUnlock()
@@ -302,6 +310,10 @@ func (ao *AdaptiveOptimizer) calculateOptimalBatchSize(throughput float64, laten
// adjustBatchSize applies the batch size adjustment
func (ao *AdaptiveOptimizer) adjustBatchSize(oldSize, newSize int, throughput float64, latency time.Duration) {
// Only adjust when indexer is actively processing
if !ao.isIndexerBusy() {
return
}
atomic.StoreInt32(&ao.batchSizeController.currentBatchSize, int32(newSize))
var reason string
@@ -329,7 +341,7 @@ func (ao *AdaptiveOptimizer) adjustBatchSize(oldSize, newSize int, throughput fl
}
ao.batchSizeController.historyMutex.Unlock()
logger.Infof("Batch size adjusted: old_size=%d, new_size=%d, reason=%s", oldSize, newSize, reason)
logger.Debugf("Batch size adjusted: old_size=%d, new_size=%d, reason=%s", oldSize, newSize, reason)
}
// performanceTrackingLoop continuously tracks performance metrics
@@ -544,6 +556,10 @@ func (ao *AdaptiveOptimizer) suggestWorkerIncrease(currentCPU, targetCPU float64
}
func (ao *AdaptiveOptimizer) suggestWorkerDecrease(currentCPU, targetCPU float64) {
// If the indexer is not busy, don't adjust workers
if !ao.isIndexerBusy() {
return
}
// If already at min workers, do nothing.
currentWorkers := int(atomic.LoadInt64(&ao.workerCount))
if currentWorkers <= ao.cpuMonitor.minWorkers {
@@ -580,6 +596,11 @@ func (ao *AdaptiveOptimizer) suggestWorkerDecrease(currentCPU, targetCPU float64
// adjustWorkerCount dynamically adjusts the worker count at runtime
func (ao *AdaptiveOptimizer) adjustWorkerCount(newCount int) {
// Only adjust when indexer is actively processing
if !ao.isIndexerBusy() {
logger.Debugf("Skipping worker adjustment while idle: requested=%d", newCount)
return
}
oldCount := int(atomic.LoadInt64(&ao.workerCount))
if newCount <= 0 || newCount == oldCount {
logger.Debugf("Skipping worker adjustment: newCount=%d, currentCount=%d", newCount, oldCount)
@@ -619,3 +640,12 @@ func min(a, b int) int {
}
return b
}
// isIndexerBusy reports whether the indexer is currently processing work.
// When no poller is configured, it returns false to avoid unintended adjustments.
func (ao *AdaptiveOptimizer) isIndexerBusy() bool {
if ao.activityPoller == nil {
return false
}
return ao.activityPoller.IsBusy()
}
+191 -18
View File
@@ -5,6 +5,9 @@ import (
"fmt"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
"sync"
"sync/atomic"
"time"
@@ -31,6 +34,12 @@ var (
lastShardUpdateAttempt int64
)
// Fallback storage when AdvancedIndexingEnabled is disabled
var (
fallbackCache = make(map[string]*NginxLogCache)
fallbackCacheMutex sync.RWMutex
)
// InitializeModernServices initializes the new modular services
func InitializeModernServices(ctx context.Context) {
servicesMutex.Lock()
@@ -229,23 +238,37 @@ const (
// AddLogPath adds a log path to the log cache with the source config file
func AddLogPath(path, logType, name, configFile string) {
manager := GetLogFileManager()
if manager != nil {
if manager := GetLogFileManager(); manager != nil {
manager.AddLogPath(path, logType, name, configFile)
} else {
// Only warn if during initialization (when it might be expected)
// Skip warning during shutdown or restart phases
return
}
// Fallback storage
fallbackCacheMutex.Lock()
fallbackCache[path] = &NginxLogCache{
Path: path,
Type: logType,
Name: name,
ConfigFile: configFile,
}
fallbackCacheMutex.Unlock()
}
// RemoveLogPathsFromConfig removes all log paths associated with a specific config file
func RemoveLogPathsFromConfig(configFile string) {
manager := GetLogFileManager()
if manager != nil {
if manager := GetLogFileManager(); manager != nil {
manager.RemoveLogPathsFromConfig(configFile)
} else {
// Silently skip if manager not available - this is normal during shutdown/restart
return
}
// Fallback removal
fallbackCacheMutex.Lock()
for p, entry := range fallbackCache {
if entry.ConfigFile == configFile {
delete(fallbackCache, p)
}
}
fallbackCacheMutex.Unlock()
}
// GetAllLogPaths returns all cached log paths, optionally filtered
@@ -253,7 +276,27 @@ func GetAllLogPaths(filters ...func(*NginxLogCache) bool) []*NginxLogCache {
if manager := GetLogFileManager(); manager != nil {
return manager.GetAllLogPaths(filters...)
}
return []*NginxLogCache{}
// Fallback list
fallbackCacheMutex.RLock()
defer fallbackCacheMutex.RUnlock()
var logs []*NginxLogCache
for _, entry := range fallbackCache {
include := true
for _, f := range filters {
if !f(entry) {
include = false
break
}
}
if include {
// Create a copy to avoid external mutation
e := *entry
logs = append(logs, &e)
}
}
return logs
}
// GetAllLogsWithIndex returns all cached log paths with their index status
@@ -261,7 +304,33 @@ func GetAllLogsWithIndex(filters ...func(*NginxLogWithIndex) bool) []*NginxLogWi
if manager := GetLogFileManager(); manager != nil {
return manager.GetAllLogsWithIndex(filters...)
}
return []*NginxLogWithIndex{}
// Fallback: produce basic entries without indexing metadata
fallbackCacheMutex.RLock()
defer fallbackCacheMutex.RUnlock()
result := make([]*NginxLogWithIndex, 0, len(fallbackCache))
for _, c := range fallbackCache {
lw := &NginxLogWithIndex{
Path: c.Path,
Type: c.Type,
Name: c.Name,
ConfigFile: c.ConfigFile,
IndexStatus: IndexStatusNotIndexed,
}
include := true
for _, f := range filters {
if !f(lw) {
include = false
break
}
}
if include {
result = append(result, lw)
}
}
return result
}
// GetAllLogsWithIndexGrouped returns logs grouped by their base name
@@ -269,7 +338,112 @@ func GetAllLogsWithIndexGrouped(filters ...func(*NginxLogWithIndex) bool) []*Ngi
if manager := GetLogFileManager(); manager != nil {
return manager.GetAllLogsWithIndexGrouped(filters...)
}
return []*NginxLogWithIndex{}
// Fallback grouping by base log name (handle simple rotation patterns)
fallbackCacheMutex.RLock()
defer fallbackCacheMutex.RUnlock()
grouped := make(map[string]*NginxLogWithIndex)
for _, c := range fallbackCache {
base := getBaseLogNameBasic(c.Path)
if existing, ok := grouped[base]; ok {
// Preserve most recent non-indexed default; nothing to aggregate in basic mode
_ = existing
continue
}
grouped[base] = &NginxLogWithIndex{
Path: base,
Type: c.Type,
Name: filepath.Base(base),
ConfigFile: c.ConfigFile,
IndexStatus: IndexStatusNotIndexed,
}
}
// Build slice and apply filters
keys := make([]string, 0, len(grouped))
for k := range grouped {
keys = append(keys, k)
}
sort.Strings(keys)
result := make([]*NginxLogWithIndex, 0, len(keys))
for _, k := range keys {
v := grouped[k]
include := true
for _, f := range filters {
if !f(v) {
include = false
break
}
}
if include {
result = append(result, v)
}
}
return result
}
// --- Fallback helpers ---
// getBaseLogNameBasic attempts to derive the base log file for a rotated file name.
// Mirrors the logic used by the indexer, simplified for basic mode.
func getBaseLogNameBasic(filePath string) string {
dir := filepath.Dir(filePath)
filename := filepath.Base(filePath)
// Remove compression extensions
for _, ext := range []string{".gz", ".bz2", ".xz", ".lz4"} {
filename = strings.TrimSuffix(filename, ext)
}
// Check YYYY.MM.DD at end
parts := strings.Split(filename, ".")
if len(parts) >= 4 {
lastThree := strings.Join(parts[len(parts)-3:], ".")
if matched, _ := regexp.MatchString(`^\d{4}\.\d{2}\.\d{2}$`, lastThree); matched {
base := strings.Join(parts[:len(parts)-3], ".")
return filepath.Join(dir, base)
}
}
// Single-part date suffix (YYYYMMDD / YYYY-MM-DD / YYMMDD)
if len(parts) >= 2 {
last := parts[len(parts)-1]
if isFullDatePatternBasic(last) {
base := strings.Join(parts[:len(parts)-1], ".")
return filepath.Join(dir, base)
}
}
// Numbered rotation: access.log.1
if m := regexp.MustCompile(`^(.+)\.(\d{1,3})$`).FindStringSubmatch(filename); len(m) > 1 {
base := m[1]
return filepath.Join(dir, base)
}
// Middle-numbered rotation: access.1.log
if m := regexp.MustCompile(`^(.+)\.(\d{1,3})\.log$`).FindStringSubmatch(filename); len(m) > 1 {
base := m[1] + ".log"
return filepath.Join(dir, base)
}
// Fallback: return original path
return filePath
}
func isFullDatePatternBasic(s string) bool {
patterns := []string{
`^\d{8}$`, // YYYYMMDD
`^\d{4}-\d{2}-\d{2}$`, // YYYY-MM-DD
`^\d{6}$`, // YYMMDD
}
for _, p := range patterns {
if matched, _ := regexp.MatchString(p, s); matched {
return true
}
}
return false
}
// SetIndexingStatus sets the indexing status for a specific file path
@@ -375,7 +549,6 @@ func updateSearcherShardsLocked() {
} else {
logger.Warn("globalSearcher is not a DistributedSearcher, cannot perform hot-swap")
}
}
// StopModernServices stops all running modern services
@@ -384,16 +557,16 @@ func StopModernServices() {
defer servicesMutex.Unlock()
if !servicesInitialized {
logger.Info("Modern nginx log services not initialized, nothing to stop")
logger.Debug("Modern nginx log services not initialized, nothing to stop")
return
}
if isShuttingDown {
logger.Info("Modern nginx log services already shutting down")
logger.Debug("Modern nginx log services already shutting down")
return
}
logger.Info("Stopping modern nginx log services...")
logger.Debug("Stopping modern nginx log services...")
isShuttingDown = true
// Cancel the service context to trigger graceful shutdown
@@ -431,7 +604,7 @@ func StopModernServices() {
shutdownCancel = nil
isShuttingDown = false
logger.Info("Modern nginx log services stopped")
logger.Debug("Modern nginx log services stopped")
}
// DestroyAllIndexes completely removes all indexed data from disk.
@@ -440,7 +613,7 @@ func DestroyAllIndexes(ctx context.Context) error {
defer servicesMutex.RUnlock()
if !servicesInitialized || globalIndexer == nil {
logger.Warn("Cannot destroy indexes, services not initialized.")
logger.Debug("Cannot destroy indexes, services not initialized.")
return fmt.Errorf("services not initialized")
}
-5
View File
@@ -131,8 +131,3 @@ func isCommentedMatch(content []byte, match [][]byte) bool {
return false
}
// GetAllLogs returns all log paths
func GetAllLogs(filters ...func(*NginxLogCache) bool) []*NginxLogCache {
return GetAllLogPaths(filters...)
}
@@ -519,22 +519,9 @@ func (ds *DistributedSearcher) SwapShards(newShards []bleve.Index) error {
}
ds.stats.mutex.Unlock()
logger.Infof("IndexAlias.Swap() completed: %d old shards -> %d new shards",
logger.Debugf("IndexAlias.Swap() completed: %d old shards -> %d new shards",
len(oldShards), len(newShards))
// Verify each new shard's document count for debugging
for i, shard := range newShards {
if shard != nil {
if docCount, err := shard.DocCount(); err != nil {
logger.Warnf("New shard %d: error getting doc count: %v", i, err)
} else {
logger.Infof("New shard %d: contains %d documents", i, docCount)
}
} else {
logger.Warnf("New shard %d: is nil", i)
}
}
// Test the searcher with a simple query to verify functionality
testCtx := context.Background()
testReq := &SearchRequest{
@@ -546,7 +533,7 @@ func (ds *DistributedSearcher) SwapShards(newShards []bleve.Index) error {
logger.Errorf("Post-swap searcher test query failed: %v", err)
return fmt.Errorf("searcher test failed after shard swap: %w", err)
} else {
logger.Info("Post-swap searcher test query succeeded")
logger.Debug("Post-swap searcher test query succeeded")
}
return nil
+50 -50
View File
@@ -40,7 +40,7 @@ func (tr *TaskRecovery) RecoverUnfinishedTasks(ctx context.Context) error {
return nil
}
logger.Info("Starting recovery of unfinished indexing tasks")
logger.Debug("Starting recovery of unfinished indexing tasks")
// Get all logs with their index status
allLogs := GetAllLogsWithIndexGrouped(func(log *NginxLogWithIndex) bool {
@@ -54,7 +54,7 @@ func (tr *TaskRecovery) RecoverUnfinishedTasks(ctx context.Context) error {
for _, log := range allLogs {
if tr.needsRecovery(log) {
incompleteTasksCount++
// Reset to queued status and assign queue position
if err := tr.recoverTask(ctx, log.Path, queuePosition); err != nil {
logger.Errorf("Failed to recover task for %s: %v", log.Path, err)
@@ -65,9 +65,9 @@ func (tr *TaskRecovery) RecoverUnfinishedTasks(ctx context.Context) error {
}
if incompleteTasksCount > 0 {
logger.Infof("Recovered %d incomplete indexing tasks", incompleteTasksCount)
logger.Debugf("Recovered %d incomplete indexing tasks", incompleteTasksCount)
} else {
logger.Info("No incomplete indexing tasks found")
logger.Debug("No incomplete indexing tasks found")
}
return nil
@@ -81,12 +81,12 @@ func (tr *TaskRecovery) needsRecovery(log *NginxLogWithIndex) bool {
// Task was in progress during last shutdown
logger.Debugf("Found incomplete indexing task: %s", log.Path)
return true
case string(indexer.IndexStatusQueued):
// Task was queued but may not have started
logger.Debugf("Found queued indexing task: %s", log.Path)
return true
case string(indexer.IndexStatusError):
// Check if error is recent (within last hour before restart)
if log.LastIndexed > 0 {
@@ -97,76 +97,76 @@ func (tr *TaskRecovery) needsRecovery(log *NginxLogWithIndex) bool {
}
}
}
return false
}
// recoverTask recovers a single indexing task
func (tr *TaskRecovery) recoverTask(ctx context.Context, logPath string, queuePosition int) error {
logger.Infof("Recovering indexing task for: %s (queue position: %d)", logPath, queuePosition)
logger.Debugf("Recovering indexing task for: %s (queue position: %d)", logPath, queuePosition)
// Set status to queued with queue position
if err := tr.setTaskStatus(logPath, string(indexer.IndexStatusQueued), queuePosition); err != nil {
return err
}
// Queue the recovery task asynchronously with proper context and WaitGroup
tr.wg.Add(1)
go tr.executeRecoveredTask(tr.ctx, logPath)
return nil
}
// executeRecoveredTask executes a recovered indexing task with proper global state and progress tracking
func (tr *TaskRecovery) executeRecoveredTask(ctx context.Context, logPath string) {
defer tr.wg.Done() // Always decrement WaitGroup
// Check context before starting
select {
case <-ctx.Done():
logger.Infof("Context cancelled, skipping recovery task for %s", logPath)
logger.Debugf("Context cancelled, skipping recovery task for %s", logPath)
return
default:
}
// Add a small delay to stagger recovery tasks, but check context
select {
case <-time.After(time.Second * 2):
case <-ctx.Done():
logger.Infof("Context cancelled during delay, skipping recovery task for %s", logPath)
logger.Debugf("Context cancelled during delay, skipping recovery task for %s", logPath)
return
}
logger.Infof("Executing recovered indexing task: %s", logPath)
logger.Debugf("Executing recovered indexing task: %s", logPath)
// Get processing manager for global state updates
processingManager := event.GetProcessingStatusManager()
// Increment active tasks counter and set global status if this is the first task
isFirstTask := atomic.AddInt32(&tr.activeTasks, 1) == 1
if isFirstTask {
processingManager.UpdateNginxLogIndexing(true)
logger.Info("Set global indexing status to true for recovery tasks")
logger.Debug("Set global indexing status to true for recovery tasks")
}
// Ensure we always decrement counter and reset global status when no tasks remain
defer func() {
remainingTasks := atomic.AddInt32(&tr.activeTasks, -1)
if remainingTasks == 0 {
processingManager.UpdateNginxLogIndexing(false)
logger.Info("Set global indexing status to false - all recovery tasks completed")
logger.Debug("Set global indexing status to false - all recovery tasks completed")
}
if r := recover(); r != nil {
logger.Errorf("Panic during recovered task execution: %v", r)
}
}()
// Set status to indexing
if err := tr.setTaskStatus(logPath, string(indexer.IndexStatusIndexing), 0); err != nil {
logger.Errorf("Failed to set indexing status for recovered task %s: %v", logPath, err)
return
}
// Create progress tracking configuration for recovery task
progressConfig := &indexer.ProgressConfig{
NotifyInterval: 1 * time.Second,
@@ -184,7 +184,7 @@ func (tr *TaskRecovery) executeRecoveredTask(ctx context.Context, logPath string
},
})
logger.Infof("Recovery progress: %s - %.1f%% (Files: %d/%d, Lines: %d/%d)",
logger.Debugf("Recovery progress: %s - %.1f%% (Files: %d/%d, Lines: %d/%d)",
progress.LogGroupPath, progress.Percentage, progress.CompletedFiles,
progress.TotalFiles, progress.ProcessedLines, progress.EstimatedLines)
},
@@ -202,10 +202,10 @@ func (tr *TaskRecovery) executeRecoveredTask(ctx context.Context, logPath string
},
})
logger.Infof("Recovery completion: %s - Success: %t, Duration: %s, Lines: %d, Size: %d bytes",
logger.Debugf("Recovery completion: %s - Success: %t, Duration: %s, Lines: %d, Size: %d bytes",
completion.LogGroupPath, completion.Success, completion.Duration,
completion.TotalLines, completion.IndexedSize)
// Send index ready event if recovery was successful
if completion.Success {
event.Publish(event.Event{
@@ -221,19 +221,19 @@ func (tr *TaskRecovery) executeRecoveredTask(ctx context.Context, logPath string
}
},
}
// Check context before starting indexing
select {
case <-ctx.Done():
logger.Infof("Context cancelled before indexing, stopping recovery task for %s", logPath)
logger.Debugf("Context cancelled before indexing, stopping recovery task for %s", logPath)
return
default:
}
// Execute the indexing with progress tracking
startTime := time.Now()
docsCountMap, minTime, maxTime, err := tr.modernIndexer.IndexLogGroupWithProgress(logPath, progressConfig)
if err != nil {
logger.Errorf("Failed to execute recovered indexing task %s: %v", logPath, err)
// Set error status
@@ -242,28 +242,28 @@ func (tr *TaskRecovery) executeRecoveredTask(ctx context.Context, logPath string
}
return
}
// Calculate total documents indexed
var totalDocsIndexed uint64
for _, docCount := range docsCountMap {
totalDocsIndexed += docCount
}
// Save indexing metadata using the log file manager
duration := time.Since(startTime)
if err := tr.logFileManager.SaveIndexMetadata(logPath, totalDocsIndexed, startTime, duration, minTime, maxTime); err != nil {
logger.Errorf("Failed to save recovered index metadata for %s: %v", logPath, err)
}
// Set status to indexed (completed)
if err := tr.setTaskStatus(logPath, string(indexer.IndexStatusIndexed), 0); err != nil {
logger.Errorf("Failed to set completed status for recovered task %s: %v", logPath, err)
}
// Update searcher shards
UpdateSearcherShards()
logger.Infof("Successfully completed recovered indexing task: %s, Documents: %d", logPath, totalDocsIndexed)
logger.Debugf("Successfully completed recovered indexing task: %s, Documents: %d", logPath, totalDocsIndexed)
}
// setTaskStatus updates the task status in the database using the enhanced persistence layer
@@ -273,33 +273,33 @@ func (tr *TaskRecovery) setTaskStatus(logPath, status string, queuePosition int)
if persistence == nil {
return fmt.Errorf("persistence manager not available")
}
// Use enhanced SetIndexStatus method
return persistence.SetIndexStatus(logPath, status, queuePosition, "")
}
// Shutdown gracefully stops all recovery tasks
func (tr *TaskRecovery) Shutdown() {
logger.Info("Shutting down task recovery system...")
logger.Debug("Shutting down task recovery system...")
// Cancel all active tasks
tr.cancel()
// Wait for all tasks to complete with timeout
done := make(chan struct{})
go func() {
tr.wg.Wait()
close(done)
}()
select {
case <-done:
logger.Info("All recovery tasks completed successfully")
logger.Debug("All recovery tasks completed successfully")
case <-time.After(30 * time.Second):
logger.Warn("Timeout waiting for recovery tasks to complete")
}
logger.Info("Task recovery system shutdown completed")
logger.Debug("Task recovery system shutdown completed")
}
// Global task recovery manager
@@ -307,16 +307,16 @@ var globalTaskRecovery *TaskRecovery
// InitTaskRecovery initializes the task recovery system - called during application startup
func InitTaskRecovery(ctx context.Context) {
logger.Info("Initializing task recovery system")
logger.Debug("Initializing task recovery system")
// Wait a bit for services to fully initialize
time.Sleep(3 * time.Second)
globalTaskRecovery = NewTaskRecovery(ctx)
if err := globalTaskRecovery.RecoverUnfinishedTasks(ctx); err != nil {
logger.Errorf("Failed to recover unfinished tasks: %v", err)
}
// Monitor context for shutdown
go func() {
<-ctx.Done()
@@ -324,4 +324,4 @@ func InitTaskRecovery(ctx context.Context) {
globalTaskRecovery.Shutdown()
}
}()
}
}
+2 -2
View File
@@ -93,7 +93,7 @@ func (sc *SiteChecker) CollectSites() {
sc.sites = make(map[string]*SiteInfo)
// Debug: log indexed sites count
logger.Infof("Found %d indexed sites", len(site.IndexedSites))
logger.Debugf("Found %d indexed sites", len(site.IndexedSites))
// Collect URLs from indexed sites, but only from enabled sites
for siteName, indexedSite := range site.IndexedSites {
@@ -143,7 +143,7 @@ func (sc *SiteChecker) CollectSites() {
}
}
logger.Infof("Collected %d enabled sites for checking", len(sc.sites))
logger.Debugf("Collected %d enabled sites for checking", len(sc.sites))
}
// loadAllSiteConfigs loads all site configs from database and caches them
+12 -12
View File
@@ -43,14 +43,14 @@ func (s *Service) waitForSiteCollection(ctx context.Context) {
// First, wait for the initial cache scan to complete
// This is much more efficient than polling
logger.Info("Waiting for initial cache scan to complete before site collection...")
logger.Debug("Waiting for initial cache scan to complete before site collection...")
cache.WaitForInitialScanComplete()
logger.Infof("Initial cache scan completed after %v, now collecting sites", time.Since(startTime))
logger.Debugf("Initial cache scan completed after %v, now collecting sites", time.Since(startTime))
// Now collect sites - the cache scanning should have populated IndexedSites
s.checker.CollectSites()
siteCount := s.checker.GetSiteCount()
logger.Infof("Site collection completed: found %d sites after %v", siteCount, time.Since(startTime))
logger.Debugf("Site collection completed: found %d sites after %v", siteCount, time.Since(startTime))
// If no sites found after cache scan, do a brief fallback check
if siteCount == 0 {
@@ -75,13 +75,13 @@ func (s *Service) waitForSiteCollection(ctx context.Context) {
siteCount, time.Since(startTime))
if siteCount > 0 {
logger.Warnf("Site collection completed via fallback: found %d sites", siteCount)
logger.Debugf("Site collection completed via fallback: found %d sites", siteCount)
return
}
// Check if we've exceeded max fallback wait time
if time.Since(startTime) >= maxWaitTime {
logger.Warnf("Site collection fallback timeout after %v - proceeding with empty site list",
logger.Debugf("Site collection fallback timeout after %v - proceeding with empty site list",
time.Since(startTime))
return
}
@@ -132,23 +132,23 @@ func (s *Service) Start() {
// Initial collection and check with delay to allow cache scanner to complete
go kernel.Run(s.ctx, "sitecheck initial collection goroutine", func(ctx context.Context) {
sl := logger.NewSessionLogger(ctx)
sl.Info("Started sitecheck initial collection goroutine")
sl.Debug("Started sitecheck initial collection goroutine")
// Give cache scanner more time to start up before checking
time.Sleep(5 * time.Second)
// Wait for cache scanner to collect sites with progressive backoff
s.waitForSiteCollection(s.ctx)
s.checker.CheckAllSites(s.ctx)
sl.Info("Sitecheck initial collection goroutine completed")
sl.Debug("Sitecheck initial collection goroutine completed")
})
// Start periodic checking (every 5 minutes)
s.ticker = time.NewTicker(5 * time.Minute)
go kernel.Run(s.ctx, "sitecheck periodic check goroutine", func(ctx context.Context) {
sl := logger.NewSessionLogger(ctx)
sl.Info("Started sitecheck periodicCheck goroutine")
sl.Debug("Started sitecheck periodicCheck goroutine")
s.periodicCheck()
sl.Info("Sitecheck periodicCheck goroutine completed")
sl.Debug("Sitecheck periodicCheck goroutine completed")
})
}
@@ -164,7 +164,7 @@ func (s *Service) Stop() {
sl := logger.NewSessionLogger(s.ctx)
s.running = false
sl.Info("Stopping site checking service")
sl.Debug("Stopping site checking service")
if s.ticker != nil {
s.ticker.Stop()
@@ -198,11 +198,11 @@ func (s *Service) periodicCheck() {
func (s *Service) RefreshSites() {
go func() {
sl := logger.NewSessionLogger(s.ctx)
sl.Info("Started sitecheck manual refresh goroutine")
sl.Debug("Started sitecheck manual refresh goroutine")
logger.Info("Manually refreshing sites")
s.checker.CollectSites()
s.checker.CheckAllSites(s.ctx)
sl.Info("Sitecheck manual refresh goroutine completed")
sl.Debug("Sitecheck manual refresh goroutine completed")
}()
}