init project
commit
28c2b2084e
|
@ -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
|
||||
)
|
|
@ -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=
|
|
@ -0,0 +1,2 @@
|
|||
2023/09/10 10:26:56 Hallo
|
||||
2023/09/10 10:26:56 Ey
|
|
@ -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)
|
||||
}
|
|
@ -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"),
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package utils
|
||||
|
||||
var logRules = map[string]string{
|
||||
"Type": "required",
|
||||
"Logs": "required",
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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{})
|
||||
}
|
|
@ -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, ¶ms); 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)
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
Loading…
Reference in New Issue