Files
nginx-ui/internal/nginx/log_path.go
2025-06-28 00:59:21 +00:00

144 lines
3.6 KiB
Go

package nginx
import (
"os"
"path/filepath"
"regexp"
"strings"
"github.com/uozi-tech/cosy/logger"
)
// Regular expressions for parsing log directives from nginx -T output
const (
// AccessLogRegexPattern matches access_log directive with unquoted path
// Matches: access_log /path/to/file
AccessLogRegexPattern = `(?m)^\s*access_log\s+([^\s;]+)`
// ErrorLogRegexPattern matches error_log directive with unquoted path
// Matches: error_log /path/to/file
ErrorLogRegexPattern = `(?m)^\s*error_log\s+([^\s;]+)`
)
var (
accessLogRegex *regexp.Regexp
errorLogRegex *regexp.Regexp
)
func init() {
accessLogRegex = regexp.MustCompile(AccessLogRegexPattern)
errorLogRegex = regexp.MustCompile(ErrorLogRegexPattern)
}
// isValidRegularFile checks if the given path is a valid regular file
// Returns true if the path exists and is a regular file (not a directory or special file)
func isValidRegularFile(path string) bool {
if path == "" {
return false
}
fileInfo, err := os.Stat(path)
if err != nil {
logger.Debug("nginx.isValidRegularFile: failed to stat file", "path", path, "error", err)
return false
}
// Check if it's a regular file (not a directory or special file)
if !fileInfo.Mode().IsRegular() {
logger.Debug("nginx.isValidRegularFile: path is not a regular file", "path", path, "mode", fileInfo.Mode())
return false
}
return true
}
// isCommentedLine checks if a line is commented (starts with #)
func isCommentedLine(line string) bool {
trimmed := strings.TrimSpace(line)
return strings.HasPrefix(trimmed, "#")
}
// getAccessLogPathFromNginxT extracts the first access_log path from nginx -T output
func getAccessLogPathFromNginxT() string {
output := getNginxT()
if output == "" {
logger.Error("nginx.getAccessLogPathFromNginxT: nginx -T output is empty")
return ""
}
lines := strings.Split(output, "\n")
for _, line := range lines {
// Skip commented lines
if isCommentedLine(line) {
continue
}
matches := accessLogRegex.FindStringSubmatch(line)
if len(matches) >= 2 {
logPath := matches[1]
// Skip 'off' directive
if logPath == "off" {
continue
}
// Handle relative paths
if !filepath.IsAbs(logPath) {
logPath = filepath.Join(GetPrefix(), logPath)
}
resolvedPath := resolvePath(logPath)
// Validate that the path is a regular file
if !isValidRegularFile(resolvedPath) {
logger.Warn("nginx.getAccessLogPathFromNginxT: path is not a valid regular file", "path", resolvedPath)
continue
}
return resolvedPath
}
}
logger.Error("nginx.getAccessLogPathFromNginxT: no valid access_log file found")
return ""
}
// getErrorLogPathFromNginxT extracts the first error_log path from nginx -T output
func getErrorLogPathFromNginxT() string {
output := getNginxT()
if output == "" {
logger.Error("nginx.getErrorLogPathFromNginxT: nginx -T output is empty")
return ""
}
lines := strings.Split(output, "\n")
for _, line := range lines {
// Skip commented lines
if isCommentedLine(line) {
continue
}
matches := errorLogRegex.FindStringSubmatch(line)
if len(matches) >= 2 {
logPath := matches[1]
// Handle relative paths
if !filepath.IsAbs(logPath) {
logPath = filepath.Join(GetPrefix(), logPath)
}
resolvedPath := resolvePath(logPath)
// Validate that the path is a regular file
if !isValidRegularFile(resolvedPath) {
logger.Warn("nginx.getErrorLogPathFromNginxT: path is not a valid regular file", "path", resolvedPath)
continue
}
return resolvedPath
}
}
logger.Error("nginx.getErrorLogPathFromNginxT: no valid error_log file found")
return ""
}