feat: read sites access log and error log

This commit is contained in:
0xJacky 2022-08-31 13:48:56 +08:00
parent ddaf3e8e60
commit 28168197b1
No known key found for this signature in database
GPG key ID: B6E4A6E4A561BAF0
5 changed files with 147 additions and 10 deletions

View file

@ -102,6 +102,13 @@ export const routes = [
path: 'error',
name: () => $gettext('Error Logs'),
component: () => import('@/views/nginx_log/NginxLog.vue'),
}, {
path: 'site',
name: () => $gettext('Site Logs'),
component: () => import('@/views/nginx_log/NginxLog.vue'),
meta: {
hiddenInSidebar: true
},
}]
},
{

View file

@ -0,0 +1,75 @@
<script setup lang="ts">
import {FileTextOutlined, FileExclamationOutlined} from '@ant-design/icons-vue'
import {computed, ref} from 'vue'
import {useRouter} from 'vue-router'
const props = defineProps(['ngx_config', 'current_server_idx', 'name'])
const accessIdx = ref()
const errorIdx = ref()
const hasAccessLog = computed(() => {
let flag = false
props.ngx_config.servers[props.current_server_idx].directives.forEach((v: any, k: any) => {
if (v.directive === 'access_log') {
flag = true
accessIdx.value = k
return
}
})
return flag
})
const hasErrorLog = computed(() => {
let flag = false
props.ngx_config.servers[props.current_server_idx].directives.forEach((v: any, k: any) => {
if (v.directive === 'error_log') {
flag = true
errorIdx.value = k
return
}
})
return flag
})
const router = useRouter()
function on_click_access_log() {
router.push({
path: '/nginx_log/site',
query: {
server_idx: props.current_server_idx,
directive_idx: accessIdx.value,
conf_name: props.name
}
})
}
function on_click_error_log() {
router.push({
path: '/nginx_log/site',
query: {
server_idx: props.current_server_idx,
directive_idx: errorIdx.value,
conf_name: props.name
}
})
}
</script>
<template>
<a-space style="margin-left: -15px;margin-bottom: 5px" v-if="hasAccessLog||hasErrorLog">
<a-button type="link" v-if="hasAccessLog" @click="on_click_access_log">
<FileTextOutlined/>
Access Logs
</a-button>
<a-button type="link" v-if="hasErrorLog" @click="on_click_error_log">
<FileExclamationOutlined/>
Error Logs
</a-button>
</a-space>
</template>
<style lang="less" scoped>
</style>

View file

@ -5,6 +5,7 @@ import {computed, ref} from 'vue'
import {useRoute} from 'vue-router'
import {useGettext} from 'vue3-gettext'
import Cert from '@/views/domain/cert/Cert.vue'
import LogEntry from '@/views/domain/ngx_conf/LogEntry.vue'
const {$gettext} = useGettext()
@ -138,6 +139,11 @@ const autoCertRef = computed({
<a-tabs v-model:activeKey="current_server_index">
<a-tab-pane :tab="'Server '+(k+1)" v-for="(v,k) in props.ngx_config.servers" :key="k">
<log-entry
:ngx_config="props.ngx_config"
:current_server_idx="current_server_index"
:name="name"
/>
<div class="tab-content">
<template v-if="current_support_ssl&&enabled">

View file

@ -1,9 +1,10 @@
<script setup lang="ts">
import {useGettext} from 'vue3-gettext'
import ws from '@/lib/websocket'
import {computed, nextTick, onMounted, onUnmounted, reactive, ref, watch} from 'vue'
import {nextTick, onMounted, onUnmounted, reactive, ref, watch} from 'vue'
import ReconnectingWebSocket from 'reconnecting-websocket'
import {useRoute} from 'vue-router'
import {useRoute, useRouter} from 'vue-router'
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
const {$gettext} = useGettext()
@ -13,17 +14,24 @@ let websocket: ReconnectingWebSocket | WebSocket
const route = useRoute()
function logType() {
return route.path.indexOf('access') > 0 ? 'access' : 'error'
return route.path.indexOf('access') > 0 ? 'access' : route.path.indexOf('error') > 0 ? 'error' : 'site'
}
const control = reactive({
fetch: 'new',
type: logType()
type: logType(),
conf_name: route.query.conf_name,
server_idx: parseInt(route.query.server_idx as string),
directive_idx: parseInt(route.query.directive_idx as string),
})
function openWs() {
websocket = ws('/api/nginx_log')
websocket.onopen = () => {
websocket.send(JSON.stringify(control))
}
websocket.onmessage = (m: any) => {
const para = document.createElement('p')
para.appendChild(document.createTextNode(m.data.trim()));
@ -76,6 +84,8 @@ onUnmounted(() => {
websocket.close()
})
const router = useRouter()
</script>
<template>
@ -96,6 +106,11 @@ onUnmounted(() => {
<pre class="nginx-log-container" ref="logContainer"></pre>
</a-card>
</a-card>
<footer-tool-bar v-if="control.type==='site'">
<a-button @click="router.go(-1)">
<translate>Back</translate>
</a-button>
</footer-tool-bar>
</template>
<style lang="less">

View file

@ -2,6 +2,7 @@ package api
import (
"encoding/json"
"github.com/0xJacky/Nginx-UI/server/pkg/nginx"
"github.com/0xJacky/Nginx-UI/server/settings"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
@ -10,11 +11,15 @@ import (
"io"
"log"
"net/http"
"path/filepath"
)
type controlStruct struct {
Fetch string `json:"fetch"`
Type string `json:"type"`
ConfName string `json:"conf_name"`
ServerIdx int `json:"server_idx"`
DirectiveIdx int `json:"directive_idx"`
}
func tailNginxLog(ws *websocket.Conn, controlChan chan controlStruct, errChan chan error) {
@ -33,11 +38,40 @@ func tailNginxLog(ws *websocket.Conn, controlChan chan controlStruct, errChan ch
seek.Offset = 0
seek.Whence = io.SeekEnd
}
var logPath string
switch control.Type {
case "site":
path := filepath.Join(nginx.GetNginxConfPath("sites-available"), control.ConfName)
config, err := nginx.ParseNgxConfig(path)
if err != nil {
errChan <- errors.Wrap(err, "error parsing ngx config")
return
}
logPath := settings.NginxLogSettings.AccessLogPath
if control.ServerIdx >= len(config.Servers) {
errChan <- errors.New("serverIdx out of range")
return
}
if control.DirectiveIdx >= len(config.Servers[control.ServerIdx].Directives) {
errChan <- errors.New("DirectiveIdx out of range")
return
}
directive := config.Servers[control.ServerIdx].Directives[control.DirectiveIdx]
if control.Type == "error" {
switch directive.Directive {
case "access_log", "error_log":
// ok
default:
errChan <- errors.New("directive.Params neither access_log nor error_log")
return
}
logPath = directive.Params
case "error":
logPath = settings.NginxLogSettings.ErrorLogPath
default:
logPath = settings.NginxLogSettings.AccessLogPath
}
// Create a tail
@ -61,7 +95,6 @@ func tailNginxLog(ws *websocket.Conn, controlChan chan controlStruct, errChan ch
return
}
case control = <-controlChan:
log.Println("control change")
next = true
break
}
@ -125,6 +158,7 @@ func NginxLog(c *gin.Context) {
if err = <-errChan; err != nil {
log.Println(err)
_ = ws.WriteMessage(websocket.TextMessage, []byte(err.Error()))
return
}
}