mirror of
https://github.com/caddyserver/caddy.git
synced 2024-11-26 02:09:47 +08:00
15fa5cf2da
OnStartup and OnShutdown callbacks now run as part of restarts, too. The startup and shutdown directives only run their commands NOT as part of restarts, as before. Some middleware that use OnStartup may need to switch to OnFirstStartup and implement OnFinalShutdown to do any cleanup as needed.
86 lines
2.4 KiB
Go
86 lines
2.4 KiB
Go
// Package log implements request (access) logging middleware.
|
|
package log
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
|
|
"github.com/mholt/caddy"
|
|
"github.com/mholt/caddy/caddyhttp/httpserver"
|
|
)
|
|
|
|
func init() {
|
|
caddy.RegisterPlugin("log", caddy.Plugin{
|
|
ServerType: "http",
|
|
Action: setup,
|
|
})
|
|
}
|
|
|
|
// Logger is a basic request logging middleware.
|
|
type Logger struct {
|
|
Next httpserver.Handler
|
|
Rules []Rule
|
|
ErrorFunc func(http.ResponseWriter, *http.Request, int) // failover error handler
|
|
}
|
|
|
|
func (l Logger) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
|
|
for _, rule := range l.Rules {
|
|
if httpserver.Path(r.URL.Path).Matches(rule.PathScope) {
|
|
// Record the response
|
|
responseRecorder := httpserver.NewResponseRecorder(w)
|
|
|
|
// Attach the Replacer we'll use so that other middlewares can
|
|
// set their own placeholders if they want to.
|
|
rep := httpserver.NewReplacer(r, responseRecorder, CommonLogEmptyValue)
|
|
responseRecorder.Replacer = rep
|
|
|
|
// Bon voyage, request!
|
|
status, err := l.Next.ServeHTTP(responseRecorder, r)
|
|
|
|
if status >= 400 {
|
|
// There was an error up the chain, but no response has been written yet.
|
|
// The error must be handled here so the log entry will record the response size.
|
|
if l.ErrorFunc != nil {
|
|
l.ErrorFunc(responseRecorder, r, status)
|
|
} else {
|
|
// Default failover error handler
|
|
responseRecorder.WriteHeader(status)
|
|
fmt.Fprintf(responseRecorder, "%d %s", status, http.StatusText(status))
|
|
}
|
|
status = 0
|
|
}
|
|
|
|
// Write log entry
|
|
rule.Log.Println(rep.Replace(rule.Format))
|
|
|
|
return status, err
|
|
}
|
|
}
|
|
return l.Next.ServeHTTP(w, r)
|
|
}
|
|
|
|
// Rule configures the logging middleware.
|
|
type Rule struct {
|
|
PathScope string
|
|
OutputFile string
|
|
Format string
|
|
Log *log.Logger
|
|
Roller *httpserver.LogRoller
|
|
file *os.File // if logging to a file that needs to be closed
|
|
}
|
|
|
|
const (
|
|
// DefaultLogFilename is the default log filename.
|
|
DefaultLogFilename = "access.log"
|
|
// CommonLogFormat is the common log format.
|
|
CommonLogFormat = `{remote} ` + CommonLogEmptyValue + ` [{when}] "{method} {uri} {proto}" {status} {size}`
|
|
// CommonLogEmptyValue is the common empty log value.
|
|
CommonLogEmptyValue = "-"
|
|
// CombinedLogFormat is the combined log format.
|
|
CombinedLogFormat = CommonLogFormat + ` "{>Referer}" "{>User-Agent}"`
|
|
// DefaultLogFormat is the default log format.
|
|
DefaultLogFormat = CommonLogFormat
|
|
)
|