feat: file/syslog output for request logging
This commit is contained in:
parent
2a37b529e8
commit
cc430b1cd0
@ -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("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.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-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{
|
var rootCmd = &cobra.Command{
|
||||||
@ -270,6 +271,9 @@ func getRunParams(flags *pflag.FlagSet, st *storage.Storage) *settings.Server {
|
|||||||
requestLogFormat := getParam(flags, "request-log-format")
|
requestLogFormat := getParam(flags, "request-log-format")
|
||||||
server.RequestLogFormat = requestLogFormat
|
server.RequestLogFormat = requestLogFormat
|
||||||
|
|
||||||
|
requestLogOutput := getParam(flags, "request-log-output")
|
||||||
|
server.RequestLogOutput = requestLogOutput
|
||||||
|
|
||||||
if val, set := getParamB(flags, "token-expiration-time"); set {
|
if val, set := getParamB(flags, "token-expiration-time"); set {
|
||||||
server.TokenExpirationTime = val
|
server.TokenExpirationTime = val
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,10 @@ package http
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"log/syslog"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -13,6 +16,78 @@ import (
|
|||||||
"github.com/tomasen/realip"
|
"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 {
|
type RequestLog struct {
|
||||||
user *users.User
|
user *users.User
|
||||||
ip string
|
ip string
|
||||||
@ -115,6 +190,34 @@ func (h *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
h.f(w, r)
|
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) {
|
func _log(writer *ResponseWriterWrapper, r *http.Request, user *users.User, server *settings.Server) {
|
||||||
log_ := RequestLog{
|
log_ := RequestLog{
|
||||||
user: user,
|
user: user,
|
||||||
@ -129,7 +232,10 @@ func _log(writer *ResponseWriterWrapper, r *http.Request, user *users.User, serv
|
|||||||
path: r.RequestURI,
|
path: r.RequestURI,
|
||||||
method: r.Method,
|
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 {
|
func RequestLogHandlerFunc(handler http.HandlerFunc, server *settings.Server) http.HandlerFunc {
|
||||||
|
|||||||
@ -52,6 +52,7 @@ type Server struct {
|
|||||||
TokenExpirationTime string `json:"tokenExpirationTime"`
|
TokenExpirationTime string `json:"tokenExpirationTime"`
|
||||||
EnableRequestLog bool `json:"enableRequestLog"`
|
EnableRequestLog bool `json:"enableRequestLog"`
|
||||||
RequestLogFormat string `json:"requestLogFormat"`
|
RequestLogFormat string `json:"requestLogFormat"`
|
||||||
|
RequestLogOutput string `json:"requestLogOutput"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean cleans any variables that might need cleaning.
|
// Clean cleans any variables that might need cleaning.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user