// SetupLogging configures logging using PocketBase's logger
func SetupLogging(srv *server.Server) {
app := srv.App()
requestStats := monitoring.NewRequestStats()
// Create a logger with common application fields
appLogger := app.Logger().With(
"pid", os.Getpid(),
"start_time", time.Now().Format(time.RFC3339),
)
app.OnServe().BindFunc(func(e *core.ServeEvent) error {
logging.SetupErrorHandler(app, e)
e.Router.BindFunc(func(c *core.RequestEvent) error {
defer func() {
RecoverFromPanic(app, c)
}()
// Generate unique trace ID
traceID := security.RandomString(18)
c.Request.Header.Set(TraceIDHeader, traceID)
c.Response.Header().Set(TraceIDHeader, traceID)
start := time.Now()
err := c.Next()
duration := time.Since(start)
logCtx := LogContext{
TraceID: traceID,
StartTime: start,
Method: c.Request.Method,
Path: c.Request.URL.Path,
StatusCode: getStatusCode(c),
Duration: duration,
UserAgent: c.Request.UserAgent(),
IP: c.Request.RemoteAddr,
}
// Track request metrics
if !shouldExcludeFromLogging(logCtx.Path) {
metrics := monitoring.RequestMetrics{
Path: logCtx.Path,
Method: logCtx.Method,
StatusCode: logCtx.StatusCode,
Duration: logCtx.Duration,
Timestamp: logCtx.StartTime,
UserAgent: logCtx.UserAgent,
ContentLength: c.Request.ContentLength,
RemoteAddr: logCtx.IP,
}
requestStats.TrackRequest(metrics)
}
// Log request
if !shouldExcludeFromLogging(logCtx.Path) {
requestLogger := app.Logger().WithGroup("request").With(
"trace_id", logCtx.TraceID,
"method", logCtx.Method,
"path", logCtx.Path,
"status", fmt.Sprintf("%d [%s]", logCtx.StatusCode, monitoring.GetStatusString(logCtx.StatusCode)),
"duration", monitoring.FormatDuration(duration),
"ip", logCtx.IP,
"user_agent", logCtx.UserAgent,
"content_length", c.Request.ContentLength,
"request_rate", requestStats.GetRequestRate(),
)
requestLogger.Debug("Request processed", "event", "http_request")
}
return err
})
return e.Next()
})
}