Enhance logging by refactoring the utility package to reduce repetition. Integrate Echo logging with zerolog. Improve server shutdown procedure to handle Ctrl+C gracefully with a 5-second delay and cancellation option via keypress.
- commit
- 8aa346e73e185d50693f815d385f14226e642c4e
- author
- bnema · · 2023-09-04 10:42 UTC
- parent
- b2b2266
- signature
- unsigned
9 files · +373 -135
M cmd/main.go +71 -6
| @@ -1,11 +1,39 @@ | |||
| 1 | 1 | package main | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | + | "net/http" | |
| 5 | + | "os" | |
| 6 | + | "os/exec" | |
| 7 | + | "os/signal" | |
| 8 | + | "syscall" | |
| 9 | + | "time" | |
| 10 | + | ||
| 11 | + | "github.com/labstack/echo/v4" | |
| 4 | 12 | "gogs.bnema.dev/gordon-echo/internal/app" | |
| 5 | 13 | "gogs.bnema.dev/gordon-echo/internal/http/routes" | |
| 14 | + | "gogs.bnema.dev/gordon-echo/pkg/docker" | |
| 15 | + | "gogs.bnema.dev/gordon-echo/pkg/utils" | |
| 6 | 16 | ) | |
| 7 | 17 | ||
| 18 | + | func setRawMode() { | |
| 19 | + | cmd := exec.Command("stty", "raw", "-echo") | |
| 20 | + | cmd.Stdin = os.Stdin | |
| 21 | + | _ = cmd.Run() | |
| 22 | + | } | |
| 23 | + | ||
| 24 | + | func restoreTerminal() { | |
| 25 | + | cmd := exec.Command("stty", "-raw", "echo") | |
| 26 | + | cmd.Stdin = os.Stdin | |
| 27 | + | _ = cmd.Run() | |
| 28 | + | } | |
| 29 | + | ||
| 8 | 30 | func main() { | |
| 31 | + | // Port = os.Getenv("PORT") or fallback to default port (1323) | |
| 32 | + | port := os.Getenv("PORT") | |
| 33 | + | if port == "" { | |
| 34 | + | port = "1323" | |
| 35 | + | } | |
| 36 | + | ||
| 9 | 37 | // Initialize Gordon | |
| 10 | 38 | gordon, err := app.NewApp() | |
| 11 | 39 | if err != nil { | |
| @@ -14,13 +42,50 @@ func main() { | |||
| 14 | 42 | return | |
| 15 | 43 | } | |
| 16 | 44 | ||
| 17 | - | // Initialize echo server with routes and middlewares | |
| 18 | - | e := routes.NewRouter(gordon) // Pass the entire 'App' instance | |
| 45 | + | docker.ListDocker() // List docker containers | |
| 46 | + | ||
| 47 | + | e := echo.New() | |
| 48 | + | e.HideBanner = true | |
| 49 | + | e.HidePort = true | |
| 50 | + | e.Logger = utils.NewEchoLoggerWrapper(gordon.APPLogger) | |
| 51 | + | e = routes.ConfigureRouter(e, gordon) | |
| 52 | + | ||
| 53 | + | // Start the server in a separate goroutine | |
| 54 | + | go func() { | |
| 55 | + | gordon.APPLogger.Info().Msgf("Server is listening on port %s", port) | |
| 56 | + | if err := e.Start(":" + port); err != nil && err != http.ErrServerClosed { | |
| 57 | + | gordon.APPLogger.Fatal().Err(err).Msg("Failed to start the server") | |
| 58 | + | } | |
| 59 | + | }() | |
| 60 | + | ||
| 61 | + | // Catch SIGINT and SIGTERM signals without raw mode initially | |
| 62 | + | c := make(chan os.Signal, 1) | |
| 63 | + | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) | |
| 64 | + | <-c | |
| 65 | + | ||
| 66 | + | gordon.APPLogger.Warn().Msg("Graceful shutdown initiated") | |
| 67 | + | gordon.APPLogger.Warn().Msg("Server will shutdown in 5 seconds press ENTER to cancel") | |
| 68 | + | ||
| 69 | + | // Now, set raw mode | |
| 70 | + | setRawMode() | |
| 71 | + | defer restoreTerminal() // Ensure terminal is restored even if program exits unexpectedly | |
| 72 | + | ||
| 73 | + | // Channel to signal a key press | |
| 74 | + | keypress := make(chan struct{}) | |
| 75 | + | ||
| 76 | + | // Goroutine to listen for a key press | |
| 77 | + | go func() { | |
| 78 | + | var b []byte = make([]byte, 1) | |
| 79 | + | os.Stdin.Read(b) | |
| 80 | + | keypress <- struct{}{} | |
| 81 | + | }() | |
| 19 | 82 | ||
| 20 | - | if err := e.Start(":1323"); err != nil { | |
| 21 | - | gordon.APPLogger.Error().Err(err).Msg("Failed to start the server") | |
| 83 | + | // Wait for either a key press or the 5-second timer | |
| 84 | + | select { | |
| 85 | + | case <-time.After(5 * time.Second): | |
| 86 | + | gordon.APPLogger.Info().Msg("Server shutdown") | |
| 87 | + | case <-keypress: | |
| 88 | + | gordon.APPLogger.Info().Msg("Shutdown cancelled by user") | |
| 22 | 89 | } | |
| 23 | 90 | ||
| 24 | - | // Graceful shutdown | |
| 25 | - | gordon.APPLogger.Info().Msg("Server is shutting down...") | |
| 26 | 91 | } | |
| @@ -1,11 +1,39 @@ | |||||
| 1 | package main | 1 | package main | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | + | "net/http" | |||
| 5 | + | "os" | |||
| 6 | + | "os/exec" | |||
| 7 | + | "os/signal" | |||
| 8 | + | "syscall" | |||
| 9 | + | "time" | |||
| 10 | + | ||||
| 11 | + | "github.com/labstack/echo/v4" | |||
| 4 | "gogs.bnema.dev/gordon-echo/internal/app" | 12 | "gogs.bnema.dev/gordon-echo/internal/app" | ||
| 5 | "gogs.bnema.dev/gordon-echo/internal/http/routes" | 13 | "gogs.bnema.dev/gordon-echo/internal/http/routes" | ||
| 14 | + | "gogs.bnema.dev/gordon-echo/pkg/docker" | |||
| 15 | + | "gogs.bnema.dev/gordon-echo/pkg/utils" | |||
| 6 | ) | 16 | ) | ||
| 7 | 17 | ||||
| 18 | + | func setRawMode() { | |||
| 19 | + | cmd := exec.Command("stty", "raw", "-echo") | |||
| 20 | + | cmd.Stdin = os.Stdin | |||
| 21 | + | _ = cmd.Run() | |||
| 22 | + | } | |||
| 23 | + | ||||
| 24 | + | func restoreTerminal() { | |||
| 25 | + | cmd := exec.Command("stty", "-raw", "echo") | |||
| 26 | + | cmd.Stdin = os.Stdin | |||
| 27 | + | _ = cmd.Run() | |||
| 28 | + | } | |||
| 29 | + | ||||
| 8 | func main() { | 30 | func main() { | ||
| 31 | + | // Port = os.Getenv("PORT") or fallback to default port (1323) | |||
| 32 | + | port := os.Getenv("PORT") | |||
| 33 | + | if port == "" { | |||
| 34 | + | port = "1323" | |||
| 35 | + | } | |||
| 36 | + | ||||
| 9 | // Initialize Gordon | 37 | // Initialize Gordon | ||
| 10 | gordon, err := app.NewApp() | 38 | gordon, err := app.NewApp() | ||
| 11 | if err != nil { | 39 | if err != nil { | ||
| @@ -14,13 +42,50 @@ func main() { | |||||
| 14 | return | 42 | return | ||
| 15 | } | 43 | } | ||
| 16 | 44 | ||||
| 17 | - | // Initialize echo server with routes and middlewares | 45 | + | docker.ListDocker() // List docker containers |
| 18 | - | e := routes.NewRouter(gordon) // Pass the entire 'App' instance | 46 | + | |
| 47 | + | e := echo.New() | |||
| 48 | + | e.HideBanner = true | |||
| 49 | + | e.HidePort = true | |||
| 50 | + | e.Logger = utils.NewEchoLoggerWrapper(gordon.APPLogger) | |||
| 51 | + | e = routes.ConfigureRouter(e, gordon) | |||
| 52 | + | ||||
| 53 | + | // Start the server in a separate goroutine | |||
| 54 | + | go func() { | |||
| 55 | + | gordon.APPLogger.Info().Msgf("Server is listening on port %s", port) | |||
| 56 | + | if err := e.Start(":" + port); err != nil && err != http.ErrServerClosed { | |||
| 57 | + | gordon.APPLogger.Fatal().Err(err).Msg("Failed to start the server") | |||
| 58 | + | } | |||
| 59 | + | }() | |||
| 60 | + | ||||
| 61 | + | // Catch SIGINT and SIGTERM signals without raw mode initially | |||
| 62 | + | c := make(chan os.Signal, 1) | |||
| 63 | + | signal.Notify(c, syscall.SIGINT, syscall.SIGTERM) | |||
| 64 | + | <-c | |||
| 65 | + | ||||
| 66 | + | gordon.APPLogger.Warn().Msg("Graceful shutdown initiated") | |||
| 67 | + | gordon.APPLogger.Warn().Msg("Server will shutdown in 5 seconds press ENTER to cancel") | |||
| 68 | + | ||||
| 69 | + | // Now, set raw mode | |||
| 70 | + | setRawMode() | |||
| 71 | + | defer restoreTerminal() // Ensure terminal is restored even if program exits unexpectedly | |||
| 72 | + | ||||
| 73 | + | // Channel to signal a key press | |||
| 74 | + | keypress := make(chan struct{}) | |||
| 75 | + | ||||
| 76 | + | // Goroutine to listen for a key press | |||
| 77 | + | go func() { | |||
| 78 | + | var b []byte = make([]byte, 1) | |||
| 79 | + | os.Stdin.Read(b) | |||
| 80 | + | keypress <- struct{}{} | |||
| 81 | + | }() | |||
| 19 | 82 | ||||
| 20 | - | if err := e.Start(":1323"); err != nil { | 83 | + | // Wait for either a key press or the 5-second timer |
| 21 | - | gordon.APPLogger.Error().Err(err).Msg("Failed to start the server") | 84 | + | select { |
| 85 | + | case <-time.After(5 * time.Second): | |||
| 86 | + | gordon.APPLogger.Info().Msg("Server shutdown") | |||
| 87 | + | case <-keypress: | |||
| 88 | + | gordon.APPLogger.Info().Msg("Shutdown cancelled by user") | |||
| 22 | } | 89 | } | ||
| 23 | 90 | ||||
| 24 | - | // Graceful shutdown | |||
| 25 | - | gordon.APPLogger.Info().Msg("Server is shutting down...") | |||
| 26 | } | 91 | } | ||
M go.mod +11 -0
| @@ -9,9 +9,20 @@ require ( | |||
| 9 | 9 | ) | |
| 10 | 10 | ||
| 11 | 11 | require ( | |
| 12 | + | github.com/Microsoft/go-winio v0.6.1 // indirect | |
| 12 | 13 | github.com/andybalholm/cascadia v1.3.1 // indirect | |
| 14 | + | github.com/docker/distribution v2.8.2+incompatible // indirect | |
| 15 | + | github.com/docker/docker v24.0.5+incompatible // indirect | |
| 16 | + | github.com/docker/go-connections v0.4.0 // indirect | |
| 17 | + | github.com/docker/go-units v0.5.0 // indirect | |
| 18 | + | github.com/gogo/protobuf v1.3.2 // indirect | |
| 13 | 19 | github.com/golang-jwt/jwt v3.2.2+incompatible // indirect | |
| 20 | + | github.com/opencontainers/go-digest v1.0.0 // indirect | |
| 21 | + | github.com/opencontainers/image-spec v1.0.2 // indirect | |
| 22 | + | github.com/pkg/errors v0.9.1 // indirect | |
| 23 | + | golang.org/x/mod v0.8.0 // indirect | |
| 14 | 24 | golang.org/x/time v0.3.0 // indirect | |
| 25 | + | golang.org/x/tools v0.6.0 // indirect | |
| 15 | 26 | ) | |
| 16 | 27 | ||
| 17 | 28 | require ( | |
| @@ -9,9 +9,20 @@ require ( | |||||
| 9 | ) | 9 | ) | ||
| 10 | 10 | ||||
| 11 | require ( | 11 | require ( | ||
| 12 | + | github.com/Microsoft/go-winio v0.6.1 // indirect | |||
| 12 | github.com/andybalholm/cascadia v1.3.1 // indirect | 13 | github.com/andybalholm/cascadia v1.3.1 // indirect | ||
| 14 | + | github.com/docker/distribution v2.8.2+incompatible // indirect | |||
| 15 | + | github.com/docker/docker v24.0.5+incompatible // indirect | |||
| 16 | + | github.com/docker/go-connections v0.4.0 // indirect | |||
| 17 | + | github.com/docker/go-units v0.5.0 // indirect | |||
| 18 | + | github.com/gogo/protobuf v1.3.2 // indirect | |||
| 13 | github.com/golang-jwt/jwt v3.2.2+incompatible // indirect | 19 | github.com/golang-jwt/jwt v3.2.2+incompatible // indirect | ||
| 20 | + | github.com/opencontainers/go-digest v1.0.0 // indirect | |||
| 21 | + | github.com/opencontainers/image-spec v1.0.2 // indirect | |||
| 22 | + | github.com/pkg/errors v0.9.1 // indirect | |||
| 23 | + | golang.org/x/mod v0.8.0 // indirect | |||
| 14 | golang.org/x/time v0.3.0 // indirect | 24 | golang.org/x/time v0.3.0 // indirect | ||
| 25 | + | golang.org/x/tools v0.6.0 // indirect | |||
| 15 | ) | 26 | ) | ||
| 16 | 27 | ||||
| 17 | require ( | 28 | require ( | ||
M go.sum +41 -0
| @@ -1,3 +1,5 @@ | |||
| 1 | + | github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= | |
| 2 | + | github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= | |
| 1 | 3 | github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= | |
| 2 | 4 | github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= | |
| 3 | 5 | github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= | |
| @@ -6,9 +8,21 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV | |||
| 6 | 8 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |
| 7 | 9 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |
| 8 | 10 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |
| 11 | + | github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= | |
| 12 | + | github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= | |
| 13 | + | github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY= | |
| 14 | + | github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= | |
| 15 | + | github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= | |
| 16 | + | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= | |
| 17 | + | github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= | |
| 18 | + | github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= | |
| 9 | 19 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= | |
| 20 | + | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= | |
| 21 | + | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= | |
| 10 | 22 | github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= | |
| 11 | 23 | github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= | |
| 24 | + | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= | |
| 25 | + | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | |
| 12 | 26 | github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4= | |
| 13 | 27 | github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ= | |
| 14 | 28 | github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= | |
| @@ -21,6 +35,11 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k | |||
| 21 | 35 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= | |
| 22 | 36 | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= | |
| 23 | 37 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= | |
| 38 | + | github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= | |
| 39 | + | github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= | |
| 40 | + | github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= | |
| 41 | + | github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= | |
| 42 | + | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | |
| 24 | 43 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | |
| 25 | 44 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | |
| 26 | 45 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |
| @@ -36,13 +55,24 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC | |||
| 36 | 55 | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= | |
| 37 | 56 | github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= | |
| 38 | 57 | github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= | |
| 58 | + | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |
| 59 | + | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |
| 39 | 60 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | |
| 40 | 61 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |
| 62 | + | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |
| 63 | + | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | |
| 41 | 64 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | |
| 42 | 65 | golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= | |
| 43 | 66 | golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= | |
| 67 | + | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | |
| 68 | + | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | |
| 44 | 69 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | |
| 70 | + | golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= | |
| 71 | + | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= | |
| 72 | + | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |
| 45 | 73 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |
| 74 | + | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |
| 75 | + | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | |
| 46 | 76 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | |
| 47 | 77 | golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | |
| 48 | 78 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | |
| @@ -50,8 +80,12 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= | |||
| 50 | 80 | golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= | |
| 51 | 81 | golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= | |
| 52 | 82 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |
| 83 | + | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |
| 84 | + | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |
| 53 | 85 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |
| 54 | 86 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |
| 87 | + | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |
| 88 | + | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |
| 55 | 89 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |
| 56 | 90 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |
| 57 | 91 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |
| @@ -79,8 +113,15 @@ golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= | |||
| 79 | 113 | golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | |
| 80 | 114 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | |
| 81 | 115 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | |
| 116 | + | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= | |
| 117 | + | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= | |
| 82 | 118 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | |
| 119 | + | golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= | |
| 120 | + | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= | |
| 83 | 121 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |
| 122 | + | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |
| 123 | + | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |
| 124 | + | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |
| 84 | 125 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | |
| 85 | 126 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |
| 86 | 127 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |
| @@ -1,3 +1,5 @@ | |||||
| 1 | + | github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= | |||
| 2 | + | github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= | |||
| 1 | github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= | 3 | github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= | ||
| 2 | github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= | 4 | github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= | ||
| 3 | github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= | 5 | github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= | ||
| @@ -6,9 +8,21 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV | |||||
| 6 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | 8 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
| 7 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | 9 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
| 8 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | 10 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
| 11 | + | github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= | |||
| 12 | + | github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= | |||
| 13 | + | github.com/docker/docker v24.0.5+incompatible h1:WmgcE4fxyI6EEXxBRxsHnZXrO1pQ3smi0k/jho4HLeY= | |||
| 14 | + | github.com/docker/docker v24.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= | |||
| 15 | + | github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= | |||
| 16 | + | github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= | |||
| 17 | + | github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= | |||
| 18 | + | github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= | |||
| 9 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= | 19 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= | ||
| 20 | + | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= | |||
| 21 | + | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= | |||
| 10 | github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= | 22 | github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= | ||
| 11 | github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= | 23 | github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= | ||
| 24 | + | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= | |||
| 25 | + | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | |||
| 12 | github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4= | 26 | github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4= | ||
| 13 | github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ= | 27 | github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ= | ||
| 14 | github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= | 28 | github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= | ||
| @@ -21,6 +35,11 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k | |||||
| 21 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= | 35 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= | ||
| 22 | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= | 36 | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= | ||
| 23 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= | 37 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= | ||
| 38 | + | github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= | |||
| 39 | + | github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= | |||
| 40 | + | github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= | |||
| 41 | + | github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= | |||
| 42 | + | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= | |||
| 24 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | 43 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= | ||
| 25 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | 44 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
| 26 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | 45 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
| @@ -36,13 +55,24 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC | |||||
| 36 | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= | 55 | github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= | ||
| 37 | github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= | 56 | github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= | ||
| 38 | github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= | 57 | github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= | ||
| 58 | + | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |||
| 59 | + | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | |||
| 39 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | 60 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | ||
| 40 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | 61 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
| 62 | + | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | |||
| 63 | + | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | |||
| 41 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | 64 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= | ||
| 42 | golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= | 65 | golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= | ||
| 43 | golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= | 66 | golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= | ||
| 67 | + | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | |||
| 68 | + | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | |||
| 44 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | 69 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= | ||
| 70 | + | golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= | |||
| 71 | + | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= | |||
| 72 | + | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
| 45 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | 73 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||
| 74 | + | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | |||
| 75 | + | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | |||
| 46 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | 76 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= | ||
| 47 | golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | 77 | golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= | ||
| 48 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | 78 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= | ||
| @@ -50,8 +80,12 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= | |||||
| 50 | golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= | 80 | golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= | ||
| 51 | golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= | 81 | golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= | ||
| 52 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | 82 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
| 83 | + | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
| 84 | + | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
| 53 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | 85 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
| 54 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | 86 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
| 87 | + | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
| 88 | + | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
| 55 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | 89 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
| 56 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | 90 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
| 57 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | 91 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
| @@ -79,8 +113,15 @@ golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= | |||||
| 79 | golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | 113 | golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||
| 80 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | 114 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
| 81 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | 115 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||
| 116 | + | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= | |||
| 117 | + | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= | |||
| 82 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | 118 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= | ||
| 119 | + | golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= | |||
| 120 | + | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= | |||
| 83 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | 121 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
| 122 | + | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
| 123 | + | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
| 124 | + | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
| 84 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | 125 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
| 85 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | 126 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
| 86 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | 127 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||
M internal/app/app.go +13 -30
| @@ -2,64 +2,47 @@ package app | |||
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | 4 | "html/template" | |
| 5 | + | "io" | |
| 5 | 6 | "os" | |
| 6 | 7 | ||
| 7 | 8 | "github.com/rs/zerolog" | |
| 8 | 9 | "gogs.bnema.dev/gordon-echo/pkg/utils" | |
| 9 | 10 | ) | |
| 10 | 11 | ||
| 11 | - | // Define the main app struct | |
| 12 | 12 | type App struct { | |
| 13 | - | // Define the app logger | |
| 14 | - | APPLogger *utils.Logger | |
| 15 | - | // Define the HTTP logger | |
| 13 | + | APPLogger *utils.Logger | |
| 16 | 14 | HTTPLogger *utils.Logger | |
| 17 | - | // Define the app config | |
| 18 | - | Template *template.Template | |
| 19 | - | // Define the app renderer | |
| 20 | - | Renderer *utils.Renderer | |
| 21 | - | // Define the app router | |
| 15 | + | Template *template.Template | |
| 16 | + | Renderer *utils.Renderer | |
| 22 | 17 | } | |
| 23 | 18 | ||
| 24 | 19 | func NewApp() (*App, error) { | |
| 25 | 20 | app := &App{} | |
| 26 | 21 | ||
| 27 | 22 | // Initialize the general application logger | |
| 28 | - | AppLogger, err := initializeAppLogger() | |
| 29 | - | if err != nil { | |
| 30 | - | return nil, err | |
| 31 | - | } | |
| 32 | - | app.APPLogger = &utils.Logger{Logger: AppLogger} | |
| 33 | - | ||
| 23 | + | app.APPLogger = utils.NewLogger().SetOutput(initializeAppLoggerOutput()) | |
| 34 | 24 | // Initialize the HTTP logger | |
| 35 | - | HttpLogger, err := initializeHTTPLogger() | |
| 36 | - | if err != nil { | |
| 37 | - | return nil, err | |
| 38 | - | } | |
| 39 | - | app.HTTPLogger = &utils.Logger{Logger: HttpLogger} | |
| 25 | + | app.HTTPLogger = utils.NewLogger().SetOutput(initializeHTTPLoggerOutput()) | |
| 40 | 26 | ||
| 41 | 27 | return app, nil | |
| 42 | 28 | } | |
| 43 | - | func initializeAppLogger() (zerolog.Logger, error) { | |
| 29 | + | ||
| 30 | + | func initializeAppLoggerOutput() io.Writer { | |
| 44 | 31 | appLogFile, err := os.OpenFile("logs/app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | |
| 45 | 32 | if err != nil { | |
| 46 | - | return zerolog.Logger{}, err | |
| 33 | + | panic(err) | |
| 47 | 34 | } | |
| 48 | - | ||
| 49 | 35 | appConsoleWriter := zerolog.ConsoleWriter{Out: os.Stdout} | |
| 50 | - | appMulti := zerolog.MultiLevelWriter(appLogFile, appConsoleWriter) | |
| 51 | - | return zerolog.New(appMulti).With().Timestamp().Str("type", "app").Logger(), nil | |
| 36 | + | return zerolog.MultiLevelWriter(appLogFile, appConsoleWriter) | |
| 52 | 37 | } | |
| 53 | 38 | ||
| 54 | - | func initializeHTTPLogger() (zerolog.Logger, error) { | |
| 39 | + | func initializeHTTPLoggerOutput() io.Writer { | |
| 55 | 40 | httpLogFile, err := os.OpenFile("logs/http.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | |
| 56 | 41 | if err != nil { | |
| 57 | - | return zerolog.Logger{}, err | |
| 42 | + | panic(err) | |
| 58 | 43 | } | |
| 59 | - | ||
| 60 | 44 | httpConsoleWriter := zerolog.ConsoleWriter{Out: os.Stdout} | |
| 61 | - | httpMulti := zerolog.MultiLevelWriter(httpLogFile, httpConsoleWriter) | |
| 62 | - | return zerolog.New(httpMulti).With().Timestamp().Logger(), nil | |
| 45 | + | return zerolog.MultiLevelWriter(httpLogFile, httpConsoleWriter) | |
| 63 | 46 | } | |
| 64 | 47 | ||
| 65 | 48 | func SetupLogging() { | |
| @@ -2,64 +2,47 @@ package app | |||||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | "html/template" | 4 | "html/template" | ||
| 5 | + | "io" | |||
| 5 | "os" | 6 | "os" | ||
| 6 | 7 | ||||
| 7 | "github.com/rs/zerolog" | 8 | "github.com/rs/zerolog" | ||
| 8 | "gogs.bnema.dev/gordon-echo/pkg/utils" | 9 | "gogs.bnema.dev/gordon-echo/pkg/utils" | ||
| 9 | ) | 10 | ) | ||
| 10 | 11 | ||||
| 11 | - | // Define the main app struct | |||
| 12 | type App struct { | 12 | type App struct { | ||
| 13 | - | // Define the app logger | 13 | + | APPLogger *utils.Logger |
| 14 | - | APPLogger *utils.Logger | |||
| 15 | - | // Define the HTTP logger | |||
| 16 | HTTPLogger *utils.Logger | 14 | HTTPLogger *utils.Logger | ||
| 17 | - | // Define the app config | 15 | + | Template *template.Template |
| 18 | - | Template *template.Template | 16 | + | Renderer *utils.Renderer |
| 19 | - | // Define the app renderer | |||
| 20 | - | Renderer *utils.Renderer | |||
| 21 | - | // Define the app router | |||
| 22 | } | 17 | } | ||
| 23 | 18 | ||||
| 24 | func NewApp() (*App, error) { | 19 | func NewApp() (*App, error) { | ||
| 25 | app := &App{} | 20 | app := &App{} | ||
| 26 | 21 | ||||
| 27 | // Initialize the general application logger | 22 | // Initialize the general application logger | ||
| 28 | - | AppLogger, err := initializeAppLogger() | 23 | + | app.APPLogger = utils.NewLogger().SetOutput(initializeAppLoggerOutput()) |
| 29 | - | if err != nil { | |||
| 30 | - | return nil, err | |||
| 31 | - | } | |||
| 32 | - | app.APPLogger = &utils.Logger{Logger: AppLogger} | |||
| 33 | - | ||||
| 34 | // Initialize the HTTP logger | 24 | // Initialize the HTTP logger | ||
| 35 | - | HttpLogger, err := initializeHTTPLogger() | 25 | + | app.HTTPLogger = utils.NewLogger().SetOutput(initializeHTTPLoggerOutput()) |
| 36 | - | if err != nil { | |||
| 37 | - | return nil, err | |||
| 38 | - | } | |||
| 39 | - | app.HTTPLogger = &utils.Logger{Logger: HttpLogger} | |||
| 40 | 26 | ||||
| 41 | return app, nil | 27 | return app, nil | ||
| 42 | } | 28 | } | ||
| 43 | - | func initializeAppLogger() (zerolog.Logger, error) { | 29 | + | |
| 30 | + | func initializeAppLoggerOutput() io.Writer { | |||
| 44 | appLogFile, err := os.OpenFile("logs/app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | 31 | appLogFile, err := os.OpenFile("logs/app.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | ||
| 45 | if err != nil { | 32 | if err != nil { | ||
| 46 | - | return zerolog.Logger{}, err | 33 | + | panic(err) |
| 47 | } | 34 | } | ||
| 48 | - | ||||
| 49 | appConsoleWriter := zerolog.ConsoleWriter{Out: os.Stdout} | 35 | appConsoleWriter := zerolog.ConsoleWriter{Out: os.Stdout} | ||
| 50 | - | appMulti := zerolog.MultiLevelWriter(appLogFile, appConsoleWriter) | 36 | + | return zerolog.MultiLevelWriter(appLogFile, appConsoleWriter) |
| 51 | - | return zerolog.New(appMulti).With().Timestamp().Str("type", "app").Logger(), nil | |||
| 52 | } | 37 | } | ||
| 53 | 38 | ||||
| 54 | - | func initializeHTTPLogger() (zerolog.Logger, error) { | 39 | + | func initializeHTTPLoggerOutput() io.Writer { |
| 55 | httpLogFile, err := os.OpenFile("logs/http.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | 40 | httpLogFile, err := os.OpenFile("logs/http.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | ||
| 56 | if err != nil { | 41 | if err != nil { | ||
| 57 | - | return zerolog.Logger{}, err | 42 | + | panic(err) |
| 58 | } | 43 | } | ||
| 59 | - | ||||
| 60 | httpConsoleWriter := zerolog.ConsoleWriter{Out: os.Stdout} | 44 | httpConsoleWriter := zerolog.ConsoleWriter{Out: os.Stdout} | ||
| 61 | - | httpMulti := zerolog.MultiLevelWriter(httpLogFile, httpConsoleWriter) | 45 | + | return zerolog.MultiLevelWriter(httpLogFile, httpConsoleWriter) |
| 62 | - | return zerolog.New(httpMulti).With().Timestamp().Logger(), nil | |||
| 63 | } | 46 | } | ||
| 64 | 47 | ||||
| 65 | func SetupLogging() { | 48 | func SetupLogging() { | ||
M internal/http/handlers/htmx.go +1 -1
| @@ -11,7 +11,7 @@ import ( | |||
| 11 | 11 | ||
| 12 | 12 | func HTMXHandler(c echo.Context) error { | |
| 13 | 13 | // Get the logger instance | |
| 14 | - | logger := utils.NewLogger().GetTypeLogger(utils.App) | |
| 14 | + | logger := utils.NewLogger() | |
| 15 | 15 | // Detect and extract HTMX data from the request | |
| 16 | 16 | htmxRequest, err := htmx.GetRequest(c) | |
| 17 | 17 | if err != nil { | |
| @@ -11,7 +11,7 @@ import ( | |||||
| 11 | 11 | ||||
| 12 | func HTMXHandler(c echo.Context) error { | 12 | func HTMXHandler(c echo.Context) error { | ||
| 13 | // Get the logger instance | 13 | // Get the logger instance | ||
| 14 | - | logger := utils.NewLogger().GetTypeLogger(utils.App) | 14 | + | logger := utils.NewLogger() |
| 15 | // Detect and extract HTMX data from the request | 15 | // Detect and extract HTMX data from the request | ||
| 16 | htmxRequest, err := htmx.GetRequest(c) | 16 | htmxRequest, err := htmx.GetRequest(c) | ||
| 17 | if err != nil { | 17 | if err != nil { | ||
M internal/http/routes/router.go +2 -3
| @@ -7,8 +7,8 @@ import ( | |||
| 7 | 7 | "gogs.bnema.dev/gordon-echo/internal/http/middlewares" | |
| 8 | 8 | ) | |
| 9 | 9 | ||
| 10 | - | func NewRouter(app *app.App) *echo.Echo { | |
| 11 | - | e := echo.New() | |
| 10 | + | func ConfigureRouter(e *echo.Echo, app *app.App) *echo.Echo { | |
| 11 | + | // The logger is already set in main.go, so we don't need to set it again here. | |
| 12 | 12 | ||
| 13 | 13 | // Register middlewares | |
| 14 | 14 | e.Use(middlewares.NewRequestLoggerMiddleware(app.HTTPLogger.Logger)) | |
| @@ -19,7 +19,6 @@ func NewRouter(app *app.App) *echo.Echo { | |||
| 19 | 19 | ||
| 20 | 20 | return e | |
| 21 | 21 | } | |
| 22 | - | ||
| 23 | 22 | func bindStaticAdminUI(e *echo.Echo) *echo.Echo { | |
| 24 | 23 | e.GET("/admin", AdminRoute) | |
| 25 | 24 | e.GET("/htmx", handlers.HTMXHandler) | |
| @@ -7,8 +7,8 @@ import ( | |||||
| 7 | "gogs.bnema.dev/gordon-echo/internal/http/middlewares" | 7 | "gogs.bnema.dev/gordon-echo/internal/http/middlewares" | ||
| 8 | ) | 8 | ) | ||
| 9 | 9 | ||||
| 10 | - | func NewRouter(app *app.App) *echo.Echo { | 10 | + | func ConfigureRouter(e *echo.Echo, app *app.App) *echo.Echo { |
| 11 | - | e := echo.New() | 11 | + | // The logger is already set in main.go, so we don't need to set it again here. |
| 12 | 12 | ||||
| 13 | // Register middlewares | 13 | // Register middlewares | ||
| 14 | e.Use(middlewares.NewRequestLoggerMiddleware(app.HTTPLogger.Logger)) | 14 | e.Use(middlewares.NewRequestLoggerMiddleware(app.HTTPLogger.Logger)) | ||
| @@ -19,7 +19,6 @@ func NewRouter(app *app.App) *echo.Echo { | |||||
| 19 | 19 | ||||
| 20 | return e | 20 | return e | ||
| 21 | } | 21 | } | ||
| 22 | - | ||||
| 23 | func bindStaticAdminUI(e *echo.Echo) *echo.Echo { | 22 | func bindStaticAdminUI(e *echo.Echo) *echo.Echo { | ||
| 24 | e.GET("/admin", AdminRoute) | 23 | e.GET("/admin", AdminRoute) | ||
| 25 | e.GET("/htmx", handlers.HTMXHandler) | 24 | e.GET("/htmx", handlers.HTMXHandler) | ||
A pkg/docker/registry.go +26 -0
| @@ -0,0 +1,26 @@ | |||
| 1 | + | package docker | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "context" | |
| 5 | + | "fmt" | |
| 6 | + | ||
| 7 | + | "github.com/docker/docker/api/types" | |
| 8 | + | "github.com/docker/docker/client" | |
| 9 | + | ) | |
| 10 | + | ||
| 11 | + | // basic list of containers and images | |
| 12 | + | func ListDocker() { | |
| 13 | + | cli, err := client.NewClientWithOpts(client.FromEnv) | |
| 14 | + | if err != nil { | |
| 15 | + | panic(err) | |
| 16 | + | } | |
| 17 | + | ||
| 18 | + | containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{}) | |
| 19 | + | if err != nil { | |
| 20 | + | panic(err) | |
| 21 | + | } | |
| 22 | + | ||
| 23 | + | for _, container := range containers { | |
| 24 | + | fmt.Printf("%s %s\n", container.ID[:10], container.Image) | |
| 25 | + | } | |
| 26 | + | } | |
| @@ -0,0 +1,26 @@ | |||||
| 1 | + | package docker | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "context" | |||
| 5 | + | "fmt" | |||
| 6 | + | ||||
| 7 | + | "github.com/docker/docker/api/types" | |||
| 8 | + | "github.com/docker/docker/client" | |||
| 9 | + | ) | |||
| 10 | + | ||||
| 11 | + | // basic list of containers and images | |||
| 12 | + | func ListDocker() { | |||
| 13 | + | cli, err := client.NewClientWithOpts(client.FromEnv) | |||
| 14 | + | if err != nil { | |||
| 15 | + | panic(err) | |||
| 16 | + | } | |||
| 17 | + | ||||
| 18 | + | containers, err := cli.ContainerList(context.Background(), types.ContainerListOptions{}) | |||
| 19 | + | if err != nil { | |||
| 20 | + | panic(err) | |||
| 21 | + | } | |||
| 22 | + | ||||
| 23 | + | for _, container := range containers { | |||
| 24 | + | fmt.Printf("%s %s\n", container.ID[:10], container.Image) | |||
| 25 | + | } | |||
| 26 | + | } | |||
M pkg/utils/fragments.go +1 -1
| @@ -11,7 +11,7 @@ import ( | |||
| 11 | 11 | // GetHTMLFragmentByID returns the HTML fragment with the specified id | |
| 12 | 12 | func GetHTMLFragmentByID(id string, data interface{}) (string, error) { | |
| 13 | 13 | // 1. Render the template | |
| 14 | - | renderer, err := GetRenderer("components.gohtml", ui.TemplateFS, NewLogger().GetTypeLogger(App)) | |
| 14 | + | renderer, err := GetRenderer("components.gohtml", ui.TemplateFS, NewLogger()) | |
| 15 | 15 | if err != nil { | |
| 16 | 16 | return "", fmt.Errorf("failed to get renderer: %w", err) | |
| 17 | 17 | } | |
| @@ -11,7 +11,7 @@ import ( | |||||
| 11 | // GetHTMLFragmentByID returns the HTML fragment with the specified id | 11 | // GetHTMLFragmentByID returns the HTML fragment with the specified id | ||
| 12 | func GetHTMLFragmentByID(id string, data interface{}) (string, error) { | 12 | func GetHTMLFragmentByID(id string, data interface{}) (string, error) { | ||
| 13 | // 1. Render the template | 13 | // 1. Render the template | ||
| 14 | - | renderer, err := GetRenderer("components.gohtml", ui.TemplateFS, NewLogger().GetTypeLogger(App)) | 14 | + | renderer, err := GetRenderer("components.gohtml", ui.TemplateFS, NewLogger()) |
| 15 | if err != nil { | 15 | if err != nil { | ||
| 16 | return "", fmt.Errorf("failed to get renderer: %w", err) | 16 | return "", fmt.Errorf("failed to get renderer: %w", err) | ||
| 17 | } | 17 | } | ||
M pkg/utils/logger.go +207 -94
| @@ -1,87 +1,101 @@ | |||
| 1 | 1 | package utils | |
| 2 | 2 | ||
| 3 | 3 | import ( | |
| 4 | + | "fmt" | |
| 5 | + | "io" | |
| 4 | 6 | "os" | |
| 5 | - | "sync" | |
| 6 | 7 | ||
| 8 | + | "github.com/labstack/gommon/log" | |
| 7 | 9 | "github.com/rs/zerolog" | |
| 8 | 10 | ) | |
| 9 | 11 | ||
| 12 | + | type LogLevel string | |
| 13 | + | ||
| 10 | 14 | const ( | |
| 11 | - | App LoggerType = iota | |
| 12 | - | Access | |
| 13 | - | Database | |
| 14 | - | Admin | |
| 15 | - | User | |
| 16 | - | Auth | |
| 17 | - | Utils | |
| 18 | - | Render | |
| 15 | + | DEBUG LogLevel = "debug" | |
| 16 | + | INFO LogLevel = "info" | |
| 17 | + | WARN LogLevel = "warn" | |
| 18 | + | ERROR LogLevel = "error" | |
| 19 | + | FATAL LogLevel = "fatal" | |
| 20 | + | PANIC LogLevel = "panic" | |
| 19 | 21 | ) | |
| 20 | 22 | ||
| 21 | - | type LoggerType int | |
| 22 | 23 | type Logger struct { | |
| 23 | 24 | zerolog.Logger | |
| 24 | 25 | } | |
| 25 | - | type LogFileManager struct { | |
| 26 | - | files map[LoggerType]*os.File | |
| 27 | - | mu sync.Mutex | |
| 26 | + | ||
| 27 | + | type EchoLoggerWrapper struct { | |
| 28 | + | *Logger | |
| 29 | + | output io.Writer | |
| 30 | + | } | |
| 31 | + | ||
| 32 | + | // Map log levels to zerolog log functions | |
| 33 | + | func (l *Logger) getLogFunc(level LogLevel) LogFunc { | |
| 34 | + | switch level { | |
| 35 | + | case DEBUG: | |
| 36 | + | return func() *zerolog.Event { return l.Logger.Debug() } | |
| 37 | + | case INFO: | |
| 38 | + | return func() *zerolog.Event { return l.Logger.Info() } | |
| 39 | + | case WARN: | |
| 40 | + | return func() *zerolog.Event { return l.Logger.Warn() } | |
| 41 | + | case ERROR: | |
| 42 | + | return func() *zerolog.Event { return l.Logger.Error() } | |
| 43 | + | case FATAL: | |
| 44 | + | return func() *zerolog.Event { return l.Logger.Fatal() } | |
| 45 | + | case PANIC: | |
| 46 | + | return func() *zerolog.Event { return l.Logger.Panic() } | |
| 47 | + | default: | |
| 48 | + | return func() *zerolog.Event { return l.Logger.Info() } // default to INFO if unknown level | |
| 49 | + | } | |
| 50 | + | } | |
| 51 | + | ||
| 52 | + | // LogFunc is a function that logs a message with optional context. | |
| 53 | + | type LogFunc func() *zerolog.Event | |
| 54 | + | ||
| 55 | + | func (l *Logger) Log(level LogLevel, i ...interface{}) { | |
| 56 | + | logFunc := l.getLogFunc(level) | |
| 57 | + | logFunc().Msg(fmt.Sprint(i...)) | |
| 28 | 58 | } | |
| 29 | 59 | ||
| 30 | - | // NewLogger returns a new logger instance | |
| 31 | 60 | func NewLogger() *Logger { | |
| 32 | 61 | writer := zerolog.ConsoleWriter{Out: os.Stdout} | |
| 33 | - | ||
| 34 | - | // Create a new logger | |
| 35 | 62 | zl := zerolog.New(writer).With().Timestamp().Logger() | |
| 36 | 63 | return &Logger{zl} | |
| 37 | 64 | } | |
| 38 | 65 | ||
| 39 | - | // NewLogFileManager returns a new log file manager | |
| 40 | - | func NewLogFileManager() *LogFileManager { | |
| 41 | - | return &LogFileManager{ | |
| 42 | - | files: make(map[LoggerType]*os.File), | |
| 43 | - | } | |
| 66 | + | func NewEchoLoggerWrapper(l *Logger) *EchoLoggerWrapper { | |
| 67 | + | return &EchoLoggerWrapper{Logger: l, output: os.Stdout} | |
| 44 | 68 | } | |
| 45 | 69 | ||
| 46 | - | // GetTypeLogger returns a logger with the specified type | |
| 47 | - | func (l *Logger) GetTypeLogger(loggerType LoggerType) *Logger { | |
| 48 | - | switch loggerType { | |
| 49 | - | case App: | |
| 50 | - | return &Logger{l.With().Str("type", "app").Logger()} | |
| 51 | - | case Access: | |
| 52 | - | return &Logger{l.With().Str("type", "access").Logger()} | |
| 53 | - | case Database: | |
| 54 | - | return &Logger{l.With().Str("type", "database").Logger()} | |
| 55 | - | case Admin: | |
| 56 | - | return &Logger{l.With().Str("type", "admin").Logger()} | |
| 57 | - | case User: | |
| 58 | - | return &Logger{l.With().Str("type", "user").Logger()} | |
| 59 | - | case Auth: | |
| 60 | - | return &Logger{l.With().Str("type", "auth").Logger()} | |
| 61 | - | default: | |
| 62 | - | return &Logger{l.With().Str("type", "undefined").Logger()} | |
| 63 | - | } | |
| 70 | + | func (l *Logger) SetOutput(w io.Writer) *Logger { | |
| 71 | + | l.Logger = l.Logger.Output(w) | |
| 72 | + | return l | |
| 64 | 73 | } | |
| 65 | 74 | ||
| 66 | - | // GetTypeLogger returns a logger with the specified type | |
| 67 | - | func (m *LogFileManager) OpenLogFile(loggerType LoggerType) (*os.File, error) { | |
| 68 | - | m.mu.Lock() | |
| 69 | - | defer m.mu.Unlock() | |
| 70 | - | ||
| 71 | - | if file, exists := m.files[loggerType]; exists { | |
| 72 | - | return file, nil | |
| 73 | - | } | |
| 75 | + | func (l *Logger) SetLevel(level LogLevel) *Logger { | |
| 76 | + | l.Logger = l.Logger.Level(getZerologLevel(level)) | |
| 77 | + | return l | |
| 78 | + | } | |
| 74 | 79 | ||
| 75 | - | logFilePath := GetLogFileForType(loggerType) | |
| 76 | - | logFile, err := os.OpenFile(logFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | |
| 77 | - | if err != nil { | |
| 78 | - | return nil, err | |
| 80 | + | func getZerologLevel(level LogLevel) zerolog.Level { | |
| 81 | + | switch level { | |
| 82 | + | case DEBUG: | |
| 83 | + | return zerolog.DebugLevel | |
| 84 | + | case INFO: | |
| 85 | + | return zerolog.InfoLevel | |
| 86 | + | case WARN: | |
| 87 | + | return zerolog.WarnLevel | |
| 88 | + | case ERROR: | |
| 89 | + | return zerolog.ErrorLevel | |
| 90 | + | case FATAL: | |
| 91 | + | return zerolog.FatalLevel | |
| 92 | + | case PANIC: | |
| 93 | + | return zerolog.PanicLevel | |
| 94 | + | default: | |
| 95 | + | return zerolog.InfoLevel // default to INFO if unknown level | |
| 79 | 96 | } | |
| 80 | - | m.files[loggerType] = logFile | |
| 81 | - | return logFile, nil | |
| 82 | 97 | } | |
| 83 | 98 | ||
| 84 | - | // CreateLogsDir creates the logs directory if it doesn't exist | |
| 85 | 99 | func CreateLogsDir() error { | |
| 86 | 100 | if _, err := os.Stat("logs"); os.IsNotExist(err) { | |
| 87 | 101 | err := os.Mkdir("logs", 0755) | |
| @@ -92,51 +106,150 @@ func CreateLogsDir() error { | |||
| 92 | 106 | return nil | |
| 93 | 107 | } | |
| 94 | 108 | ||
| 95 | - | // GetLogFileForType returns the log file for the specified logger type | |
| 96 | - | func GetLogFileForType(loggerType LoggerType) string { | |
| 97 | - | switch loggerType { | |
| 98 | - | case App, Database, Utils, Render: | |
| 99 | - | return "logs/app.log" | |
| 100 | - | case Access, Admin, User, Auth: | |
| 101 | - | return "logs/http.log" | |
| 102 | - | default: | |
| 103 | - | return "logs/undefined.log" | |
| 104 | - | } | |
| 109 | + | func (l *EchoLoggerWrapper) Output() io.Writer { | |
| 110 | + | return l.output | |
| 105 | 111 | } | |
| 106 | 112 | ||
| 107 | - | // CreateLogFile creates a log file for each logger type | |
| 108 | - | func CreateLogFile(loggerType LoggerType) (*os.File, error) { | |
| 109 | - | logFilePath := GetLogFileForType(loggerType) | |
| 110 | - | logFile, err := os.OpenFile(logFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | |
| 111 | - | if err != nil { | |
| 112 | - | return nil, err | |
| 113 | - | } | |
| 114 | - | return logFile, nil | |
| 113 | + | func (l *EchoLoggerWrapper) SetOutput(w io.Writer) { | |
| 114 | + | l.output = w | |
| 115 | 115 | } | |
| 116 | 116 | ||
| 117 | - | // GetLogLevel returns the log level for the specified logger type | |
| 118 | - | func GetLogLevel(loggerType LoggerType) zerolog.Level { | |
| 119 | - | switch loggerType { | |
| 120 | - | case App, Database, Utils, Render: | |
| 121 | - | return zerolog.InfoLevel | |
| 122 | - | case Access, Admin, User, Auth: | |
| 123 | - | return zerolog.DebugLevel | |
| 124 | - | default: | |
| 125 | - | return zerolog.DebugLevel | |
| 126 | - | } | |
| 117 | + | func (l *EchoLoggerWrapper) Prefix() string { | |
| 118 | + | return "" | |
| 127 | 119 | } | |
| 128 | 120 | ||
| 129 | - | // CloseLogFile closes the log file for the specified logger type | |
| 130 | - | func (m *LogFileManager) CloseLogFile(loggerType LoggerType) error { | |
| 131 | - | m.mu.Lock() | |
| 132 | - | defer m.mu.Unlock() | |
| 121 | + | func (l *EchoLoggerWrapper) SetPrefix(p string) { | |
| 122 | + | // do nothing | |
| 123 | + | } | |
| 133 | 124 | ||
| 134 | - | if file, exists := m.files[loggerType]; exists { | |
| 135 | - | err := file.Close() | |
| 136 | - | if err != nil { | |
| 137 | - | return err | |
| 138 | - | } | |
| 139 | - | delete(m.files, loggerType) | |
| 140 | - | } | |
| 141 | - | return nil | |
| 125 | + | func (l *EchoLoggerWrapper) Level() log.Lvl { | |
| 126 | + | return log.Lvl(l.Logger.GetLevel()) | |
| 127 | + | } | |
| 128 | + | ||
| 129 | + | // SetHeader | |
| 130 | + | func (l *EchoLoggerWrapper) SetHeader(h string) { | |
| 131 | + | // do nothing | |
| 132 | + | } | |
| 133 | + | ||
| 134 | + | func (l *EchoLoggerWrapper) SetLevel(log.Lvl) { | |
| 135 | + | // do nothing | |
| 136 | + | } | |
| 137 | + | ||
| 138 | + | // SetEvent creates a new event with the given level and message. | |
| 139 | + | func (l *EchoLoggerWrapper) SetEvent(level zerolog.Level, msg string) *zerolog.Event { | |
| 140 | + | //cannot use utils.NewEchoLoggerWrapper(app.HTTPLogger) (value of type *utils.EchoLoggerWrapper) as echo.Logger value in assignment: *utils.EchoLoggerWrapper does not implement echo.Logger (wrong type for method Error) | |
| 141 | + | return l.Logger.WithLevel(level).Str("message", msg) | |
| 142 | + | } | |
| 143 | + | ||
| 144 | + | func (l *EchoLoggerWrapper) OutputStdout() bool { | |
| 145 | + | return true | |
| 146 | + | } | |
| 147 | + | ||
| 148 | + | // Helper function for methods that accept variadic slice of interfaces | |
| 149 | + | func (l *EchoLoggerWrapper) LogWithArgs(level LogLevel, i ...interface{}) { | |
| 150 | + | l.Logger.Log(level, i...) | |
| 151 | + | } | |
| 152 | + | ||
| 153 | + | // Helper function for methods that accept a format string and arguments | |
| 154 | + | func (l *EchoLoggerWrapper) LogWithFormat(level LogLevel, format string, args ...interface{}) { | |
| 155 | + | l.Logger.Log(level, fmt.Sprintf(format, args...)) | |
| 156 | + | } | |
| 157 | + | ||
| 158 | + | // Helper function for methods that accept a log.JSON object | |
| 159 | + | func (l *EchoLoggerWrapper) LogWithJSON(level LogLevel, j log.JSON) { | |
| 160 | + | l.Logger.Log(level, j) | |
| 161 | + | } | |
| 162 | + | ||
| 163 | + | // Debug | |
| 164 | + | func (l *EchoLoggerWrapper) Debug(i ...interface{}) { | |
| 165 | + | l.LogWithArgs(DEBUG, i...) | |
| 166 | + | } | |
| 167 | + | ||
| 168 | + | func (l *EchoLoggerWrapper) Debugf(format string, args ...interface{}) { | |
| 169 | + | l.LogWithFormat(DEBUG, format, args...) | |
| 170 | + | } | |
| 171 | + | ||
| 172 | + | func (l *EchoLoggerWrapper) Debugj(j log.JSON) { | |
| 173 | + | l.LogWithJSON(DEBUG, j) | |
| 174 | + | } | |
| 175 | + | ||
| 176 | + | // Info | |
| 177 | + | func (l *EchoLoggerWrapper) Info(i ...interface{}) { | |
| 178 | + | l.LogWithArgs(INFO, i...) | |
| 179 | + | } | |
| 180 | + | ||
| 181 | + | func (l *EchoLoggerWrapper) Infof(format string, args ...interface{}) { | |
| 182 | + | l.LogWithFormat(INFO, format, args...) | |
| 183 | + | } | |
| 184 | + | ||
| 185 | + | func (l *EchoLoggerWrapper) Infoj(j log.JSON) { | |
| 186 | + | l.LogWithJSON(INFO, j) | |
| 187 | + | } | |
| 188 | + | ||
| 189 | + | // Warn | |
| 190 | + | ||
| 191 | + | func (l *EchoLoggerWrapper) Warn(i ...interface{}) { | |
| 192 | + | l.LogWithArgs(WARN, i...) | |
| 193 | + | } | |
| 194 | + | ||
| 195 | + | func (l *EchoLoggerWrapper) Warnf(format string, args ...interface{}) { | |
| 196 | + | l.LogWithFormat(WARN, format, args...) | |
| 197 | + | } | |
| 198 | + | ||
| 199 | + | func (l *EchoLoggerWrapper) Warnj(j log.JSON) { | |
| 200 | + | l.LogWithJSON(WARN, j) | |
| 201 | + | } | |
| 202 | + | ||
| 203 | + | // Error | |
| 204 | + | func (l *EchoLoggerWrapper) Error(i ...interface{}) { | |
| 205 | + | l.LogWithArgs(ERROR, i...) | |
| 206 | + | } | |
| 207 | + | ||
| 208 | + | func (l *EchoLoggerWrapper) Errorf(format string, args ...interface{}) { | |
| 209 | + | l.LogWithFormat(ERROR, format, args...) | |
| 210 | + | } | |
| 211 | + | ||
| 212 | + | func (l *EchoLoggerWrapper) Errorj(j log.JSON) { | |
| 213 | + | l.LogWithJSON(ERROR, j) | |
| 214 | + | } | |
| 215 | + | ||
| 216 | + | // Fatal | |
| 217 | + | func (l *EchoLoggerWrapper) Fatal(i ...interface{}) { | |
| 218 | + | l.LogWithArgs(FATAL, i...) | |
| 219 | + | } | |
| 220 | + | ||
| 221 | + | func (l *EchoLoggerWrapper) Fatalf(format string, args ...interface{}) { | |
| 222 | + | l.LogWithFormat(FATAL, format, args...) | |
| 223 | + | } | |
| 224 | + | ||
| 225 | + | func (l *EchoLoggerWrapper) Fatalj(j log.JSON) { | |
| 226 | + | l.LogWithJSON(FATAL, j) | |
| 227 | + | } | |
| 228 | + | ||
| 229 | + | // Panic | |
| 230 | + | ||
| 231 | + | func (l *EchoLoggerWrapper) Panic(i ...interface{}) { | |
| 232 | + | l.LogWithArgs(PANIC, i...) | |
| 233 | + | } | |
| 234 | + | ||
| 235 | + | func (l *EchoLoggerWrapper) Panicf(format string, args ...interface{}) { | |
| 236 | + | l.LogWithFormat(PANIC, format, args...) | |
| 237 | + | } | |
| 238 | + | ||
| 239 | + | func (l *EchoLoggerWrapper) Panicj(j log.JSON) { | |
| 240 | + | l.LogWithJSON(PANIC, j) | |
| 241 | + | } | |
| 242 | + | ||
| 243 | + | ||
| 244 | + | ||
| 245 | + | func (l *EchoLoggerWrapper) Print(i ...interface{}) { | |
| 246 | + | l.LogWithArgs(INFO, i...) | |
| 247 | + | } | |
| 248 | + | ||
| 249 | + | func (l *EchoLoggerWrapper) Printf(format string, args ...interface{}) { | |
| 250 | + | l.LogWithFormat(INFO, format, args...) | |
| 251 | + | } | |
| 252 | + | ||
| 253 | + | func (l *EchoLoggerWrapper) Printj(j log.JSON) { | |
| 254 | + | l.LogWithJSON(INFO, j) | |
| 142 | 255 | } | |
| @@ -1,87 +1,101 @@ | |||||
| 1 | package utils | 1 | package utils | ||
| 2 | 2 | ||||
| 3 | import ( | 3 | import ( | ||
| 4 | + | "fmt" | |||
| 5 | + | "io" | |||
| 4 | "os" | 6 | "os" | ||
| 5 | - | "sync" | |||
| 6 | 7 | ||||
| 8 | + | "github.com/labstack/gommon/log" | |||
| 7 | "github.com/rs/zerolog" | 9 | "github.com/rs/zerolog" | ||
| 8 | ) | 10 | ) | ||
| 9 | 11 | ||||
| 12 | + | type LogLevel string | |||
| 13 | + | ||||
| 10 | const ( | 14 | const ( | ||
| 11 | - | App LoggerType = iota | 15 | + | DEBUG LogLevel = "debug" |
| 12 | - | Access | 16 | + | INFO LogLevel = "info" |
| 13 | - | Database | 17 | + | WARN LogLevel = "warn" |
| 14 | - | Admin | 18 | + | ERROR LogLevel = "error" |
| 15 | - | User | 19 | + | FATAL LogLevel = "fatal" |
| 16 | - | Auth | 20 | + | PANIC LogLevel = "panic" |
| 17 | - | Utils | |||
| 18 | - | Render | |||
| 19 | ) | 21 | ) | ||
| 20 | 22 | ||||
| 21 | - | type LoggerType int | |||
| 22 | type Logger struct { | 23 | type Logger struct { | ||
| 23 | zerolog.Logger | 24 | zerolog.Logger | ||
| 24 | } | 25 | } | ||
| 25 | - | type LogFileManager struct { | 26 | + | |
| 26 | - | files map[LoggerType]*os.File | 27 | + | type EchoLoggerWrapper struct { |
| 27 | - | mu sync.Mutex | 28 | + | *Logger |
| 29 | + | output io.Writer | |||
| 30 | + | } | |||
| 31 | + | ||||
| 32 | + | // Map log levels to zerolog log functions | |||
| 33 | + | func (l *Logger) getLogFunc(level LogLevel) LogFunc { | |||
| 34 | + | switch level { | |||
| 35 | + | case DEBUG: | |||
| 36 | + | return func() *zerolog.Event { return l.Logger.Debug() } | |||
| 37 | + | case INFO: | |||
| 38 | + | return func() *zerolog.Event { return l.Logger.Info() } | |||
| 39 | + | case WARN: | |||
| 40 | + | return func() *zerolog.Event { return l.Logger.Warn() } | |||
| 41 | + | case ERROR: | |||
| 42 | + | return func() *zerolog.Event { return l.Logger.Error() } | |||
| 43 | + | case FATAL: | |||
| 44 | + | return func() *zerolog.Event { return l.Logger.Fatal() } | |||
| 45 | + | case PANIC: | |||
| 46 | + | return func() *zerolog.Event { return l.Logger.Panic() } | |||
| 47 | + | default: | |||
| 48 | + | return func() *zerolog.Event { return l.Logger.Info() } // default to INFO if unknown level | |||
| 49 | + | } | |||
| 50 | + | } | |||
| 51 | + | ||||
| 52 | + | // LogFunc is a function that logs a message with optional context. | |||
| 53 | + | type LogFunc func() *zerolog.Event | |||
| 54 | + | ||||
| 55 | + | func (l *Logger) Log(level LogLevel, i ...interface{}) { | |||
| 56 | + | logFunc := l.getLogFunc(level) | |||
| 57 | + | logFunc().Msg(fmt.Sprint(i...)) | |||
| 28 | } | 58 | } | ||
| 29 | 59 | ||||
| 30 | - | // NewLogger returns a new logger instance | |||
| 31 | func NewLogger() *Logger { | 60 | func NewLogger() *Logger { | ||
| 32 | writer := zerolog.ConsoleWriter{Out: os.Stdout} | 61 | writer := zerolog.ConsoleWriter{Out: os.Stdout} | ||
| 33 | - | ||||
| 34 | - | // Create a new logger | |||
| 35 | zl := zerolog.New(writer).With().Timestamp().Logger() | 62 | zl := zerolog.New(writer).With().Timestamp().Logger() | ||
| 36 | return &Logger{zl} | 63 | return &Logger{zl} | ||
| 37 | } | 64 | } | ||
| 38 | 65 | ||||
| 39 | - | // NewLogFileManager returns a new log file manager | 66 | + | func NewEchoLoggerWrapper(l *Logger) *EchoLoggerWrapper { |
| 40 | - | func NewLogFileManager() *LogFileManager { | 67 | + | return &EchoLoggerWrapper{Logger: l, output: os.Stdout} |
| 41 | - | return &LogFileManager{ | |||
| 42 | - | files: make(map[LoggerType]*os.File), | |||
| 43 | - | } | |||
| 44 | } | 68 | } | ||
| 45 | 69 | ||||
| 46 | - | // GetTypeLogger returns a logger with the specified type | 70 | + | func (l *Logger) SetOutput(w io.Writer) *Logger { |
| 47 | - | func (l *Logger) GetTypeLogger(loggerType LoggerType) *Logger { | 71 | + | l.Logger = l.Logger.Output(w) |
| 48 | - | switch loggerType { | 72 | + | return l |
| 49 | - | case App: | |||
| 50 | - | return &Logger{l.With().Str("type", "app").Logger()} | |||
| 51 | - | case Access: | |||
| 52 | - | return &Logger{l.With().Str("type", "access").Logger()} | |||
| 53 | - | case Database: | |||
| 54 | - | return &Logger{l.With().Str("type", "database").Logger()} | |||
| 55 | - | case Admin: | |||
| 56 | - | return &Logger{l.With().Str("type", "admin").Logger()} | |||
| 57 | - | case User: | |||
| 58 | - | return &Logger{l.With().Str("type", "user").Logger()} | |||
| 59 | - | case Auth: | |||
| 60 | - | return &Logger{l.With().Str("type", "auth").Logger()} | |||
| 61 | - | default: | |||
| 62 | - | return &Logger{l.With().Str("type", "undefined").Logger()} | |||
| 63 | - | } | |||
| 64 | } | 73 | } | ||
| 65 | 74 | ||||
| 66 | - | // GetTypeLogger returns a logger with the specified type | 75 | + | func (l *Logger) SetLevel(level LogLevel) *Logger { |
| 67 | - | func (m *LogFileManager) OpenLogFile(loggerType LoggerType) (*os.File, error) { | 76 | + | l.Logger = l.Logger.Level(getZerologLevel(level)) |
| 68 | - | m.mu.Lock() | 77 | + | return l |
| 69 | - | defer m.mu.Unlock() | 78 | + | } |
| 70 | - | ||||
| 71 | - | if file, exists := m.files[loggerType]; exists { | |||
| 72 | - | return file, nil | |||
| 73 | - | } | |||
| 74 | 79 | ||||
| 75 | - | logFilePath := GetLogFileForType(loggerType) | 80 | + | func getZerologLevel(level LogLevel) zerolog.Level { |
| 76 | - | logFile, err := os.OpenFile(logFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | 81 | + | switch level { |
| 77 | - | if err != nil { | 82 | + | case DEBUG: |
| 78 | - | return nil, err | 83 | + | return zerolog.DebugLevel |
| 84 | + | case INFO: | |||
| 85 | + | return zerolog.InfoLevel | |||
| 86 | + | case WARN: | |||
| 87 | + | return zerolog.WarnLevel | |||
| 88 | + | case ERROR: | |||
| 89 | + | return zerolog.ErrorLevel | |||
| 90 | + | case FATAL: | |||
| 91 | + | return zerolog.FatalLevel | |||
| 92 | + | case PANIC: | |||
| 93 | + | return zerolog.PanicLevel | |||
| 94 | + | default: | |||
| 95 | + | return zerolog.InfoLevel // default to INFO if unknown level | |||
| 79 | } | 96 | } | ||
| 80 | - | m.files[loggerType] = logFile | |||
| 81 | - | return logFile, nil | |||
| 82 | } | 97 | } | ||
| 83 | 98 | ||||
| 84 | - | // CreateLogsDir creates the logs directory if it doesn't exist | |||
| 85 | func CreateLogsDir() error { | 99 | func CreateLogsDir() error { | ||
| 86 | if _, err := os.Stat("logs"); os.IsNotExist(err) { | 100 | if _, err := os.Stat("logs"); os.IsNotExist(err) { | ||
| 87 | err := os.Mkdir("logs", 0755) | 101 | err := os.Mkdir("logs", 0755) | ||
| @@ -92,51 +106,150 @@ func CreateLogsDir() error { | |||||
| 92 | return nil | 106 | return nil | ||
| 93 | } | 107 | } | ||
| 94 | 108 | ||||
| 95 | - | // GetLogFileForType returns the log file for the specified logger type | 109 | + | func (l *EchoLoggerWrapper) Output() io.Writer { |
| 96 | - | func GetLogFileForType(loggerType LoggerType) string { | 110 | + | return l.output |
| 97 | - | switch loggerType { | |||
| 98 | - | case App, Database, Utils, Render: | |||
| 99 | - | return "logs/app.log" | |||
| 100 | - | case Access, Admin, User, Auth: | |||
| 101 | - | return "logs/http.log" | |||
| 102 | - | default: | |||
| 103 | - | return "logs/undefined.log" | |||
| 104 | - | } | |||
| 105 | } | 111 | } | ||
| 106 | 112 | ||||
| 107 | - | // CreateLogFile creates a log file for each logger type | 113 | + | func (l *EchoLoggerWrapper) SetOutput(w io.Writer) { |
| 108 | - | func CreateLogFile(loggerType LoggerType) (*os.File, error) { | 114 | + | l.output = w |
| 109 | - | logFilePath := GetLogFileForType(loggerType) | |||
| 110 | - | logFile, err := os.OpenFile(logFilePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) | |||
| 111 | - | if err != nil { | |||
| 112 | - | return nil, err | |||
| 113 | - | } | |||
| 114 | - | return logFile, nil | |||
| 115 | } | 115 | } | ||
| 116 | 116 | ||||
| 117 | - | // GetLogLevel returns the log level for the specified logger type | 117 | + | func (l *EchoLoggerWrapper) Prefix() string { |
| 118 | - | func GetLogLevel(loggerType LoggerType) zerolog.Level { | 118 | + | return "" |
| 119 | - | switch loggerType { | |||
| 120 | - | case App, Database, Utils, Render: | |||
| 121 | - | return zerolog.InfoLevel | |||
| 122 | - | case Access, Admin, User, Auth: | |||
| 123 | - | return zerolog.DebugLevel | |||
| 124 | - | default: | |||
| 125 | - | return zerolog.DebugLevel | |||
| 126 | - | } | |||
| 127 | } | 119 | } | ||
| 128 | 120 | ||||
| 129 | - | // CloseLogFile closes the log file for the specified logger type | 121 | + | func (l *EchoLoggerWrapper) SetPrefix(p string) { |
| 130 | - | func (m *LogFileManager) CloseLogFile(loggerType LoggerType) error { | 122 | + | // do nothing |
| 131 | - | m.mu.Lock() | 123 | + | } |
| 132 | - | defer m.mu.Unlock() | |||
| 133 | 124 | ||||
| 134 | - | if file, exists := m.files[loggerType]; exists { | 125 | + | func (l *EchoLoggerWrapper) Level() log.Lvl { |
| 135 | - | err := file.Close() | 126 | + | return log.Lvl(l.Logger.GetLevel()) |
| 136 | - | if err != nil { | 127 | + | } |
| 137 | - | return err | 128 | + | |
| 138 | - | } | 129 | + | // SetHeader |
| 139 | - | delete(m.files, loggerType) | 130 | + | func (l *EchoLoggerWrapper) SetHeader(h string) { |
| 140 | - | } | 131 | + | // do nothing |
| 141 | - | return nil | 132 | + | } |
| 133 | + | ||||
| 134 | + | func (l *EchoLoggerWrapper) SetLevel(log.Lvl) { | |||
| 135 | + | // do nothing | |||
| 136 | + | } | |||
| 137 | + | ||||
| 138 | + | // SetEvent creates a new event with the given level and message. | |||
| 139 | + | func (l *EchoLoggerWrapper) SetEvent(level zerolog.Level, msg string) *zerolog.Event { | |||
| 140 | + | //cannot use utils.NewEchoLoggerWrapper(app.HTTPLogger) (value of type *utils.EchoLoggerWrapper) as echo.Logger value in assignment: *utils.EchoLoggerWrapper does not implement echo.Logger (wrong type for method Error) | |||
| 141 | + | return l.Logger.WithLevel(level).Str("message", msg) | |||
| 142 | + | } | |||
| 143 | + | ||||
| 144 | + | func (l *EchoLoggerWrapper) OutputStdout() bool { | |||
| 145 | + | return true | |||
| 146 | + | } | |||
| 147 | + | ||||
| 148 | + | // Helper function for methods that accept variadic slice of interfaces | |||
| 149 | + | func (l *EchoLoggerWrapper) LogWithArgs(level LogLevel, i ...interface{}) { | |||
| 150 | + | l.Logger.Log(level, i...) | |||
| 151 | + | } | |||
| 152 | + | ||||
| 153 | + | // Helper function for methods that accept a format string and arguments | |||
| 154 | + | func (l *EchoLoggerWrapper) LogWithFormat(level LogLevel, format string, args ...interface{}) { | |||
| 155 | + | l.Logger.Log(level, fmt.Sprintf(format, args...)) | |||
| 156 | + | } | |||
| 157 | + | ||||
| 158 | + | // Helper function for methods that accept a log.JSON object | |||
| 159 | + | func (l *EchoLoggerWrapper) LogWithJSON(level LogLevel, j log.JSON) { | |||
| 160 | + | l.Logger.Log(level, j) | |||
| 161 | + | } | |||
| 162 | + | ||||
| 163 | + | // Debug | |||
| 164 | + | func (l *EchoLoggerWrapper) Debug(i ...interface{}) { | |||
| 165 | + | l.LogWithArgs(DEBUG, i...) | |||
| 166 | + | } | |||
| 167 | + | ||||
| 168 | + | func (l *EchoLoggerWrapper) Debugf(format string, args ...interface{}) { | |||
| 169 | + | l.LogWithFormat(DEBUG, format, args...) | |||
| 170 | + | } | |||
| 171 | + | ||||
| 172 | + | func (l *EchoLoggerWrapper) Debugj(j log.JSON) { | |||
| 173 | + | l.LogWithJSON(DEBUG, j) | |||
| 174 | + | } | |||
| 175 | + | ||||
| 176 | + | // Info | |||
| 177 | + | func (l *EchoLoggerWrapper) Info(i ...interface{}) { | |||
| 178 | + | l.LogWithArgs(INFO, i...) | |||
| 179 | + | } | |||
| 180 | + | ||||
| 181 | + | func (l *EchoLoggerWrapper) Infof(format string, args ...interface{}) { | |||
| 182 | + | l.LogWithFormat(INFO, format, args...) | |||
| 183 | + | } | |||
| 184 | + | ||||
| 185 | + | func (l *EchoLoggerWrapper) Infoj(j log.JSON) { | |||
| 186 | + | l.LogWithJSON(INFO, j) | |||
| 187 | + | } | |||
| 188 | + | ||||
| 189 | + | // Warn | |||
| 190 | + | ||||
| 191 | + | func (l *EchoLoggerWrapper) Warn(i ...interface{}) { | |||
| 192 | + | l.LogWithArgs(WARN, i...) | |||
| 193 | + | } | |||
| 194 | + | ||||
| 195 | + | func (l *EchoLoggerWrapper) Warnf(format string, args ...interface{}) { | |||
| 196 | + | l.LogWithFormat(WARN, format, args...) | |||
| 197 | + | } | |||
| 198 | + | ||||
| 199 | + | func (l *EchoLoggerWrapper) Warnj(j log.JSON) { | |||
| 200 | + | l.LogWithJSON(WARN, j) | |||
| 201 | + | } | |||
| 202 | + | ||||
| 203 | + | // Error | |||
| 204 | + | func (l *EchoLoggerWrapper) Error(i ...interface{}) { | |||
| 205 | + | l.LogWithArgs(ERROR, i...) | |||
| 206 | + | } | |||
| 207 | + | ||||
| 208 | + | func (l *EchoLoggerWrapper) Errorf(format string, args ...interface{}) { | |||
| 209 | + | l.LogWithFormat(ERROR, format, args...) | |||
| 210 | + | } | |||
| 211 | + | ||||
| 212 | + | func (l *EchoLoggerWrapper) Errorj(j log.JSON) { | |||
| 213 | + | l.LogWithJSON(ERROR, j) | |||
| 214 | + | } | |||
| 215 | + | ||||
| 216 | + | // Fatal | |||
| 217 | + | func (l *EchoLoggerWrapper) Fatal(i ...interface{}) { | |||
| 218 | + | l.LogWithArgs(FATAL, i...) | |||
| 219 | + | } | |||
| 220 | + | ||||
| 221 | + | func (l *EchoLoggerWrapper) Fatalf(format string, args ...interface{}) { | |||
| 222 | + | l.LogWithFormat(FATAL, format, args...) | |||
| 223 | + | } | |||
| 224 | + | ||||
| 225 | + | func (l *EchoLoggerWrapper) Fatalj(j log.JSON) { | |||
| 226 | + | l.LogWithJSON(FATAL, j) | |||
| 227 | + | } | |||
| 228 | + | ||||
| 229 | + | // Panic | |||
| 230 | + | ||||
| 231 | + | func (l *EchoLoggerWrapper) Panic(i ...interface{}) { | |||
| 232 | + | l.LogWithArgs(PANIC, i...) | |||
| 233 | + | } | |||
| 234 | + | ||||
| 235 | + | func (l *EchoLoggerWrapper) Panicf(format string, args ...interface{}) { | |||
| 236 | + | l.LogWithFormat(PANIC, format, args...) | |||
| 237 | + | } | |||
| 238 | + | ||||
| 239 | + | func (l *EchoLoggerWrapper) Panicj(j log.JSON) { | |||
| 240 | + | l.LogWithJSON(PANIC, j) | |||
| 241 | + | } | |||
| 242 | + | ||||
| 243 | + | ||||
| 244 | + | ||||
| 245 | + | func (l *EchoLoggerWrapper) Print(i ...interface{}) { | |||
| 246 | + | l.LogWithArgs(INFO, i...) | |||
| 247 | + | } | |||
| 248 | + | ||||
| 249 | + | func (l *EchoLoggerWrapper) Printf(format string, args ...interface{}) { | |||
| 250 | + | l.LogWithFormat(INFO, format, args...) | |||
| 251 | + | } | |||
| 252 | + | ||||
| 253 | + | func (l *EchoLoggerWrapper) Printj(j log.JSON) { | |||
| 254 | + | l.LogWithJSON(INFO, j) | |||
| 142 | } | 255 | } | ||