DB 시간포멧 수정. access log 추가
This commit is contained in:
@@ -3,13 +3,18 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||
|
||||
"geoip-rest/internal/geo"
|
||||
"geoip-rest/internal/schedule"
|
||||
@@ -45,6 +50,8 @@ func main() {
|
||||
ReadBufferSize: 16 * 1024, // allow larger request headers (e.g., proxy cookies)
|
||||
})
|
||||
|
||||
app.Use(newFileLogger(env("ACCESS_LOG_PATH", "/log/api-access.log")))
|
||||
|
||||
app.Get("/", func(c *fiber.Ctx) error {
|
||||
return c.JSON(fiber.Map{
|
||||
"service": "geoip-rest",
|
||||
@@ -107,6 +114,86 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func newFileLogger(path string) fiber.Handler {
|
||||
if path == "" {
|
||||
return func(c *fiber.Ctx) error { return c.Next() }
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||
log.Printf("access log disabled (mkdir failed: %v)", err)
|
||||
return func(c *fiber.Ctx) error { return c.Next() }
|
||||
}
|
||||
maxBytes := int64(envInt("ACCESS_LOG_MAX_BYTES", 10*1024*1024))
|
||||
writer, err := newRotatingWriter(path, maxBytes)
|
||||
if err != nil {
|
||||
log.Printf("access log disabled (open failed: %v)", err)
|
||||
return func(c *fiber.Ctx) error { return c.Next() }
|
||||
}
|
||||
|
||||
format := "${time} ${ip} ${method} ${path} ${protocol} ${status} ${latency_human} headers=${reqHeaders}\n"
|
||||
cfg := logger.Config{
|
||||
Format: format,
|
||||
TimeFormat: time.RFC3339,
|
||||
TimeZone: "Asia/Seoul",
|
||||
Output: writer,
|
||||
}
|
||||
return logger.New(cfg)
|
||||
}
|
||||
|
||||
type rotatingWriter struct {
|
||||
mu sync.Mutex
|
||||
path string
|
||||
maxBytes int64
|
||||
file *os.File
|
||||
}
|
||||
|
||||
func newRotatingWriter(path string, maxBytes int64) (*rotatingWriter, error) {
|
||||
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &rotatingWriter{
|
||||
path: path,
|
||||
maxBytes: maxBytes,
|
||||
file: f,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (w *rotatingWriter) Write(p []byte) (int, error) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
|
||||
if err := w.rotateIfNeeded(len(p)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return w.file.Write(p)
|
||||
}
|
||||
|
||||
func (w *rotatingWriter) rotateIfNeeded(incoming int) error {
|
||||
info, err := w.file.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if info.Size()+int64(incoming) <= w.maxBytes {
|
||||
return nil
|
||||
}
|
||||
_ = w.file.Close()
|
||||
|
||||
ts := time.Now().Format("20060102-150405")
|
||||
rotated := fmt.Sprintf("%s.%s", w.path, ts)
|
||||
if err := os.Rename(w.path, rotated); err != nil {
|
||||
// attempt to reopen original to keep logging
|
||||
w.file, _ = os.OpenFile(w.path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
|
||||
return err
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(w.path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.file = f
|
||||
return nil
|
||||
}
|
||||
|
||||
func env(key, fallback string) string {
|
||||
if val := os.Getenv(key); val != "" {
|
||||
return val
|
||||
@@ -129,6 +216,18 @@ func envBool(key string, fallback bool) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func envInt(key string, fallback int) int {
|
||||
val := os.Getenv(key)
|
||||
if val == "" {
|
||||
return fallback
|
||||
}
|
||||
parsed, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
return fallback
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
func sanitizeDBURL(raw string) string {
|
||||
u, err := url.Parse(raw)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user