init project

main
alex 2023-09-10 13:53:57 +02:00
commit 28c2b2084e
12 changed files with 461 additions and 0 deletions

30
go.mod Normal file
View File

@ -0,0 +1,30 @@
module jannex/log-manager
go 1.21.0
require (
github.com/gofiber/fiber/v2 v2.49.1
github.com/joho/godotenv v1.5.1
)
require (
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.15.3 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/klauspost/compress v1.16.7 // indirect
github.com/leodido/go-urn v1.2.4 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.49.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sys v0.11.0 // indirect
golang.org/x/text v0.8.0 // indirect
)

57
go.sum Normal file
View File

@ -0,0 +1,57 @@
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.15.3 h1:S+sSpunYjNPDuXkWbK+x+bA7iXiW296KG4dL3X7xUZo=
github.com/go-playground/validator/v10 v10.15.3/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/gofiber/fiber/v2 v2.49.1 h1:0W2DRWevSirc8pJl4o8r8QejDR8TV6ZUCawHxwbIdOk=
github.com/gofiber/fiber/v2 v2.49.1/go.mod h1:nPUeEBUeeYGgwbDm59Gp7vS8MDyScL6ezr/Np9A13WU=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.49.0 h1:9FdvCpmxB74LH4dPb7IJ1cOSsluR07XG3I1txXWwJpE=
github.com/valyala/fasthttp v1.49.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

2
grouptasks.log Normal file
View File

@ -0,0 +1,2 @@
2023/09/10 10:26:56 Hallo
2023/09/10 10:26:56 Ey

34
main.go Normal file
View File

@ -0,0 +1,34 @@
package main
import (
"jannex/log-manager/modules/config"
"jannex/log-manager/modules/utils"
"jannex/log-manager/routers/router"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/gofiber/fiber/v2/middleware/logger"
)
func init() {
config.LoadConfig()
utils.ValidatorInit()
utils.CreateDirectoryIfNotExists(config.Cfg.LogFolder)
}
func main() {
app := fiber.New(fiber.Config{
BodyLimit: 100 * 1024 * 1024,
})
app.Use(cors.New())
app.Use(logger.New(logger.Config{
Format: "${pid} ${locals:requestid} ${status} - ${latency} ${method} ${path}\n",
}))
router.SetupRoutes(app)
app.Listen(config.Cfg.Host + ":" + config.Cfg.Port)
}

33
modules/config/config.go Normal file
View File

@ -0,0 +1,33 @@
package config
import (
"fmt"
"os"
"github.com/joho/godotenv"
)
var Cfg Config
type Config struct {
Host string
Port string
LogFolder string
}
func LoadConfig() {
// used to determine server was startet in docker or not
if os.Getenv("DOCKER") == "" {
fmt.Println("Load env from file")
godotenv.Load(".env")
} else {
fmt.Println("Load env from system")
}
Cfg = Config{
Host: os.Getenv("HOST"),
Port: os.Getenv("PORT"),
LogFolder: os.Getenv("LOG_FOLDER"),
}
}

View File

@ -0,0 +1,113 @@
package loghandler
import (
"bufio"
"fmt"
"jannex/log-manager/modules/config"
"jannex/log-manager/modules/structs"
"jannex/log-manager/modules/utils"
"os"
"strconv"
"sync"
"time"
)
var FileMutexMap = make(map[string]*sync.Mutex)
var FileMutexMapLock sync.Mutex
func getFileMutex(filePath string) *sync.Mutex {
FileMutexMapLock.Lock()
defer FileMutexMapLock.Unlock()
mutex, ok := FileMutexMap[filePath]
if !ok {
mutex = &sync.Mutex{}
FileMutexMap[filePath] = mutex
}
return mutex
}
func AddLog(body structs.LogBody) {
year, month, day := time.Now().Date()
logFolder := config.Cfg.LogFolder
utils.CreateDirectoryIfNotExists(logFolder + body.Type)
path := logFolder + body.Type + "/" + strconv.Itoa(day) + "-" + strconv.Itoa(int(month)) + "-" + strconv.Itoa(year) + ".log"
// get the mutex for this file
mutex := getFileMutex(path)
// lock the mutex to ensure the file is only opened once at a time
mutex.Lock()
defer mutex.Unlock()
file, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
for _, log := range body.Logs {
if _, err := fmt.Fprintln(file, log); err != nil {
fmt.Println(err)
}
}
}
func GetAvailableLogFiles(logType string) ([]string, error) {
var availableLogs []string
path := config.Cfg.LogFolder + logType
files, err := os.ReadDir(path)
if err != nil {
fmt.Println(err)
return []string{}, err
}
for _, file := range files {
availableLogs = append(availableLogs, file.Name())
}
return availableLogs, nil
}
func GetLogByDate(logType string, date string) ([]string, error) {
var logs []string
path := config.Cfg.LogFolder + logType + "/" + date + ".log"
// get the mutex for this file
mutex := getFileMutex(path)
// lock the mutex to ensure the file is only opened once at a time
mutex.Lock()
defer mutex.Unlock()
file, err := os.Open(path)
if err != nil {
fmt.Println(err)
return []string{}, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
logs = append(logs, scanner.Text())
}
if len(logs) == 0 {
return []string{}, nil
}
return logs, nil
}

16
modules/structs/log.go Normal file
View File

@ -0,0 +1,16 @@
package structs
type LogBody struct {
Type string
Logs []string
}
// /log/grouptasks?d=2021-08-01&f=i
type GetLogParams struct {
Type string
}
type GetLogQuery struct {
D string // date
F string // filter
}

6
modules/utils/globals.go Normal file
View File

@ -0,0 +1,6 @@
package utils
var logRules = map[string]string{
"Type": "required",
"Logs": "required",
}

51
modules/utils/utils.go Normal file
View File

@ -0,0 +1,51 @@
package utils
import (
"errors"
"os"
"github.com/gofiber/fiber/v2"
)
func ParamsParserHelper(c *fiber.Ctx, params interface{}) error {
if err := c.ParamsParser(params); err != nil {
return errors.New("Failed to parse params")
}
if errValidation := ValidateStruct(params); errValidation != nil {
return errors.New("Failed to validate params")
}
return nil
}
func BodyParserHelper(c *fiber.Ctx, body interface{}) error {
if err := c.BodyParser(body); err != nil {
return errors.New("Failed to parse body")
}
if errValidation := ValidateStruct(body); errValidation != nil {
return errors.New("Failed to validate body")
}
return nil
}
func QueryParserHelper(c *fiber.Ctx, query interface{}) error {
if err := c.QueryParser(query); err != nil {
return errors.New("Failed to parse query")
}
if errValidation := ValidateStruct(query); errValidation != nil {
return errors.New("Failed to validate query")
}
return nil
}
func CreateDirectoryIfNotExists(path string) {
if _, err := os.Stat(path); os.IsNotExist(err) {
os.Mkdir(path, 0755)
}
}

View File

@ -0,0 +1,37 @@
package utils
import (
"jannex/log-manager/modules/structs"
"github.com/go-playground/validator/v10"
)
type ErrorResponse struct {
FailedField string
Tag string
Value string
}
var Validate = validator.New()
func ValidateStruct(event interface{}) []*ErrorResponse {
var errors []*ErrorResponse
err := Validate.Struct(event)
if err != nil {
for _, err := range err.(validator.ValidationErrors) {
var element ErrorResponse
element.FailedField = err.StructNamespace()
element.Tag = err.Tag()
element.Value = err.Param()
errors = append(errors, &element)
}
}
return errors
}
func ValidatorInit() {
Validate.RegisterStructValidationMapRules(logRules,
structs.LogBody{},
structs.GetLogParams{},
structs.GetLogQuery{})
}

View File

@ -0,0 +1,67 @@
package log
import (
"fmt"
"jannex/log-manager/modules/loghandler"
"jannex/log-manager/modules/structs"
"jannex/log-manager/modules/utils"
"github.com/gofiber/fiber/v2"
)
func AddLog(c *fiber.Ctx) error {
var body structs.LogBody
fmt.Println("c", string(c.Body()))
if err := utils.BodyParserHelper(c, &body); err != nil {
return c.SendStatus(fiber.StatusBadRequest)
}
fmt.Println("body", body)
loghandler.AddLog(body)
return c.SendStatus(fiber.StatusOK)
}
func GetLog(c *fiber.Ctx) error {
var params structs.GetLogParams
if err := utils.ParamsParserHelper(c, &params); err != nil {
return c.SendStatus(fiber.StatusBadRequest)
}
var query structs.GetLogQuery
if err := utils.QueryParserHelper(c, &query); err != nil {
return c.SendStatus(fiber.StatusBadRequest)
}
fmt.Println("params", params, "query", query)
// no type specified
if params.Type == "" {
return c.SendStatus(fiber.StatusBadRequest)
}
// no date specified -> return all available files
if query.D == "" {
availableLogs, err := loghandler.GetAvailableLogFiles(params.Type)
if err != nil {
return c.SendStatus(fiber.StatusUnprocessableEntity)
}
return c.JSON(availableLogs)
}
logs, err := loghandler.GetLogByDate(params.Type, query.D)
if err != nil {
return c.SendStatus(fiber.StatusUnprocessableEntity)
}
return c.JSON(logs)
}

15
routers/router/router.go Normal file
View File

@ -0,0 +1,15 @@
package router
import (
"jannex/log-manager/routers/router/api/v1/log"
"github.com/gofiber/fiber/v2"
)
func SetupRoutes(app *fiber.App) {
v1 := app.Group("/v1")
l := v1.Group("/log")
l.Post("/", log.AddLog)
l.Get("/:type", log.GetLog)
}