feat: file/syslog output for request logging

This commit is contained in:
wwt 2023-12-22 19:15:53 +08:00
parent 2a37b529e8
commit cc430b1cd0
3 changed files with 112 additions and 1 deletions

View File

@ -72,6 +72,7 @@ func addServerFlags(flags *pflag.FlagSet) {
flags.Bool("disable-type-detection-by-header", false, "disables type detection by reading file headers")
flags.Bool("enable-request-log", false, "enable logging all the request")
flags.String("request-log-format", "%{user_name} %{ip} %{method} %{path} %{response_size}", "logging format for the request")
flags.String("request-log-output", "system", "destination for request logs, available options: system (golang logging), file://path/to/log.txt (local file), udp://host:port (syslog server by UDP), tcp://host:port (syslog server by TCP). By default: system.")
}
var rootCmd = &cobra.Command{
@ -270,6 +271,9 @@ func getRunParams(flags *pflag.FlagSet, st *storage.Storage) *settings.Server {
requestLogFormat := getParam(flags, "request-log-format")
server.RequestLogFormat = requestLogFormat
requestLogOutput := getParam(flags, "request-log-output")
server.RequestLogOutput = requestLogOutput
if val, set := getParamB(flags, "token-expiration-time"); set {
server.TokenExpirationTime = val
}

View File

@ -3,7 +3,10 @@ package http
import (
"fmt"
"log"
"log/syslog"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"
@ -13,6 +16,78 @@ import (
"github.com/tomasen/realip"
)
type LogWriter struct {
Type string
Uri string
syslogWriter *syslog.Writer
fileWriter *os.File
}
var globalLogWriter *LogWriter = nil
func _syslogConnect(type_ string, host string) *syslog.Writer {
writer, err := syslog.Dial(type_, host, syslog.LOG_EMERG|syslog.LOG_SYSLOG, "filebrowser")
if err != nil {
log.Printf("ERROR: fail to connect to the syslog-%s server: %s", type_, host)
log.Println(err)
return nil
} else {
return writer
}
}
func (w *LogWriter) Connect() bool {
if w.Type == "system" {
return true
}
if w.Type == "file" && w.fileWriter != nil {
return true
}
if (w.Type == "syslog-tcp" || w.Type == "syslog-udp") && w.syslogWriter != nil {
return true
}
if w.Type == "file" {
w.fileWriter = _openFile(w.Uri)
} else if w.Type == "syslog-udp" {
w.syslogWriter = _syslogConnect("udp", w.Uri)
} else if w.Type == "syslog-tcp" {
w.syslogWriter = _syslogConnect("tcp", w.Uri)
}
return w.syslogWriter != nil || w.fileWriter != nil
}
func _openFile(path string) *os.File {
d := filepath.Dir(path)
err := os.MkdirAll(d, 0644)
if err != nil {
log.Println("ERROR: fail to create dir " + d)
return nil
}
file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0644)
if err != nil {
log.Println("ERROR: fail to open file " + path)
log.Println(err)
return nil
}
return file
}
func (w *LogWriter) Write(msg string) {
if w.Type == "system" {
log.Println(msg)
} else if w.Type == "file" {
if w.Connect() {
w.fileWriter.Write([]byte(msg + "\n"))
}
} else if w.Type == "syslog-udp" || w.Type == "syslog-tcp" {
if w.Connect() {
w.syslogWriter.Emerg(msg)
}
} else {
log.Println("Unsupported request log output type " + w.Type)
}
}
type RequestLog struct {
user *users.User
ip string
@ -115,6 +190,34 @@ func (h *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.f(w, r)
}
func _logToOutput(msg string, writer *LogWriter) {
if writer != nil {
writer.Write(msg)
}
}
func _getLogWriter(output string) *LogWriter {
if output == "system" {
return &LogWriter{Type: "system"}
} else if strings.HasPrefix(output, "udp://") {
return &LogWriter{Type: "syslog-udp", Uri: output[6:]}
} else if strings.HasPrefix(output, "tcp://") {
return &LogWriter{Type: "syslog-tcp", Uri: output[6:]}
} else if strings.HasPrefix(output, "file://") {
return &LogWriter{Type: "file", Uri: output[7:]}
}
log.Fatal("Unsupported log output: " + output)
return &LogWriter{}
}
func _globalLogWriter(output string) *LogWriter {
if globalLogWriter == nil {
globalLogWriter = _getLogWriter(output)
}
return globalLogWriter
}
func _log(writer *ResponseWriterWrapper, r *http.Request, user *users.User, server *settings.Server) {
log_ := RequestLog{
user: user,
@ -129,7 +232,10 @@ func _log(writer *ResponseWriterWrapper, r *http.Request, user *users.User, serv
path: r.RequestURI,
method: r.Method,
}
log.Println(formatLog(server.RequestLogFormat, log_))
if log_.status == 0 {
log_.status = 200
}
_globalLogWriter(server.RequestLogOutput).Write(formatLog(server.RequestLogFormat, log_))
}
func RequestLogHandlerFunc(handler http.HandlerFunc, server *settings.Server) http.HandlerFunc {

View File

@ -52,6 +52,7 @@ type Server struct {
TokenExpirationTime string `json:"tokenExpirationTime"`
EnableRequestLog bool `json:"enableRequestLog"`
RequestLogFormat string `json:"requestLogFormat"`
RequestLogOutput string `json:"requestLogOutput"`
}
// Clean cleans any variables that might need cleaning.