Compare commits

..

4 Commits

Author SHA1 Message Date
4d57cf827d
refactor(handler): Move array manipulation
All checks were successful
ci/woodpecker/push/build Pipeline was successful
2024-12-17 16:07:40 +01:00
df9f7fdc13
feat(handlers): Added info logging 2024-12-17 16:07:02 +01:00
cdd2b5e250
feat(logging): Debug logging 2024-12-17 15:48:12 +01:00
94b766f106
feat(logger): Log levels 2024-12-17 15:45:40 +01:00
8 changed files with 97 additions and 16 deletions

1
.env
View File

@ -1,3 +1,4 @@
LOGLEVEL=debug
PORT=3000 PORT=3000
PRODUCION=false PRODUCION=false
APIKEY=lfk APIKEY=lfk

View File

@ -20,6 +20,8 @@ import (
// @Router /v1/barcodes/{type}/{content} [get] // @Router /v1/barcodes/{type}/{content} [get]
func (h *DefaultHandler) GenerateBarcode(c *fiber.Ctx) error { func (h *DefaultHandler) GenerateBarcode(c *fiber.Ctx) error {
logger := h.Logger.Named("GenerateBarcode")
// Get the type and content from the URL // Get the type and content from the URL
barcodeType := c.Params("type") barcodeType := c.Params("type")
barcodeContent := c.Params("content") barcodeContent := c.Params("content")
@ -32,6 +34,7 @@ func (h *DefaultHandler) GenerateBarcode(c *fiber.Ctx) error {
// Convert width and height to integers // Convert width and height to integers
width, err := strconv.Atoi(widthStr) width, err := strconv.Atoi(widthStr)
if err != nil { if err != nil {
logger.Errorw("Invalid width parameter", "width", widthStr, "error", err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Invalid width parameter", "error": "Invalid width parameter",
}) })
@ -39,6 +42,7 @@ func (h *DefaultHandler) GenerateBarcode(c *fiber.Ctx) error {
height, err := strconv.Atoi(heightStr) height, err := strconv.Atoi(heightStr)
if err != nil { if err != nil {
logger.Errorw("Invalid height parameter", "height", heightStr, "error", err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Invalid height parameter", "error": "Invalid height parameter",
}) })
@ -46,18 +50,23 @@ func (h *DefaultHandler) GenerateBarcode(c *fiber.Ctx) error {
padding, err := strconv.Atoi(paddingStr) padding, err := strconv.Atoi(paddingStr)
if err != nil { if err != nil {
logger.Errorw("Invalid padding parameter", "padding", paddingStr, "error", err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Invalid padding parameter", "error": "Invalid padding parameter",
}) })
} }
logger = logger.With("type", barcodeType, "content", barcodeContent, "width", width, "height", height, "padding", padding)
// Generate the barcode // Generate the barcode
logger.Info("Generating barcode")
barcode, err := h.BarcodeService.GenerateBarcode(barcodeType, barcodeContent, width, height, padding) barcode, err := h.BarcodeService.GenerateBarcode(barcodeType, barcodeContent, width, height, padding)
if err != nil { if err != nil {
logger.Errorw("Failed to generate barcode", "error", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": err.Error(), "error": err.Error(),
}) })
} }
logger.Info("Barcode generated")
c.Set(fiber.HeaderContentType, "image/png") c.Set(fiber.HeaderContentType, "image/png")
return c.Send(barcode.Bytes()) return c.Send(barcode.Bytes())

View File

@ -1,7 +1,6 @@
package handlers package handlers
import ( import (
"log"
"slices" "slices"
"git.odit.services/lfk/document-server/models" "git.odit.services/lfk/document-server/models"
@ -19,27 +18,35 @@ import (
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /v1/pdfs/cards [post] // @Router /v1/pdfs/cards [post]
func (h *DefaultHandler) GenerateCard(c *fiber.Ctx) error { func (h *DefaultHandler) GenerateCard(c *fiber.Ctx) error {
logger := h.Logger.Named("GenerateCard")
cardRequest := new(models.CardRequest) cardRequest := new(models.CardRequest)
if err := c.BodyParser(cardRequest); err != nil { if err := c.BodyParser(cardRequest); err != nil {
logger.Errorw("Invalid request", "error", err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": err.Error(), "error": err.Error(),
}) })
} }
if !slices.Contains([]string{"en", "de"}, cardRequest.Locale) { if !slices.Contains([]string{"en", "de"}, cardRequest.Locale) {
logger.Errorw("Invalid locale", "locale", cardRequest.Locale)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Invalid locale", "error": "Invalid locale",
}) })
} }
logger = logger.With("locale", cardRequest.Locale)
templateString, err := h.StaticService.GetTemplate(cardRequest.Locale, "card") templateString, err := h.StaticService.GetTemplate(cardRequest.Locale, "card")
if err != nil { if err != nil {
log.Println(err) logger.Errorw("Template not found", "error", err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Template not found", "error": "Template not found",
}) })
} }
template, err := h.Templater.StringToTemplate(templateString) template, err := h.Templater.StringToTemplate(templateString)
if err != nil { if err != nil {
logger.Errorw("Error parsing template", "error", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": err.Error(), "error": err.Error(),
}) })
@ -53,20 +60,26 @@ func (h *DefaultHandler) GenerateCard(c *fiber.Ctx) error {
BarcodePrefix: h.Config.CardBarcodePrefix, BarcodePrefix: h.Config.CardBarcodePrefix,
} }
logger.Info("Generating card html")
result, err := h.Templater.Execute(template, genConfig) result, err := h.Templater.Execute(template, genConfig)
if err != nil { if err != nil {
logger.Errorw("Error executing template", "error", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": err.Error(), "error": err.Error(),
}) })
} }
logger.Info("Generated card html")
c.Set(fiber.HeaderContentType, "text/html") c.Set(fiber.HeaderContentType, "text/html")
logger.Info("Converting html to pdf")
pdf, err := h.Converter.ToPdf(result, "a4", false) pdf, err := h.Converter.ToPdf(result, "a4", false)
if err != nil { if err != nil {
logger.Errorw("Error converting html to pdf", "error", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": err.Error(), "error": err.Error(),
}) })
} }
logger.Info("Converted html to pdf")
c.Set(fiber.HeaderContentType, "application/pdf") c.Set(fiber.HeaderContentType, "application/pdf")
c.Set(fiber.HeaderContentDisposition, "attachment; filename=runner-cards.pdf") c.Set(fiber.HeaderContentDisposition, "attachment; filename=runner-cards.pdf")

View File

@ -1,7 +1,6 @@
package handlers package handlers
import ( import (
"log"
"slices" "slices"
"git.odit.services/lfk/document-server/models" "git.odit.services/lfk/document-server/models"
@ -19,27 +18,35 @@ import (
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /v1/pdfs/certificates [post] // @Router /v1/pdfs/certificates [post]
func (h *DefaultHandler) GenerateCertificate(c *fiber.Ctx) error { func (h *DefaultHandler) GenerateCertificate(c *fiber.Ctx) error {
logger := h.Logger.Named("GenerateCertificate")
certificateRequest := new(models.CertificateRequest) certificateRequest := new(models.CertificateRequest)
if err := c.BodyParser(certificateRequest); err != nil { if err := c.BodyParser(certificateRequest); err != nil {
logger.Errorw("Invalid request", "error", err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": err.Error(), "error": err.Error(),
}) })
} }
if !slices.Contains([]string{"en", "de"}, certificateRequest.Locale) { if !slices.Contains([]string{"en", "de"}, certificateRequest.Locale) {
logger.Errorw("Invalid locale", "locale", certificateRequest.Locale)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Invalid locale", "error": "Invalid locale",
}) })
} }
logger = logger.With("locale", certificateRequest.Locale)
templateString, err := h.StaticService.GetTemplate(certificateRequest.Locale, "certificate") templateString, err := h.StaticService.GetTemplate(certificateRequest.Locale, "certificate")
if err != nil { if err != nil {
log.Println(err) logger.Errorw("Template not found", "error", err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Template not found", "error": "Template not found",
}) })
} }
template, err := h.Templater.StringToTemplate(templateString) template, err := h.Templater.StringToTemplate(templateString)
if err != nil { if err != nil {
logger.Errorw("Error parsing template", "error", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": err.Error(), "error": err.Error(),
}) })
@ -53,20 +60,24 @@ func (h *DefaultHandler) GenerateCertificate(c *fiber.Ctx) error {
Locale: certificateRequest.Locale, Locale: certificateRequest.Locale,
} }
logger.Info("Generating certificate html")
result, err := h.Templater.Execute(template, genConfig) result, err := h.Templater.Execute(template, genConfig)
if err != nil { if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": err.Error(), "error": err.Error(),
}) })
} }
logger.Info("Generated card html")
c.Set(fiber.HeaderContentType, "text/html") c.Set(fiber.HeaderContentType, "text/html")
logger.Info("Converting html to pdf")
pdf, err := h.Converter.ToPdf(result, "a4", false) pdf, err := h.Converter.ToPdf(result, "a4", false)
if err != nil { if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": err.Error(), "error": err.Error(),
}) })
} }
logger.Info("Converted html to pdf")
c.Set(fiber.HeaderContentType, "application/pdf") c.Set(fiber.HeaderContentType, "application/pdf")
c.Set(fiber.HeaderContentDisposition, "attachment; filename=certificate.pdf") c.Set(fiber.HeaderContentDisposition, "attachment; filename=certificate.pdf")

View File

@ -1,7 +1,6 @@
package handlers package handlers
import ( import (
"log"
"slices" "slices"
"git.odit.services/lfk/document-server/models" "git.odit.services/lfk/document-server/models"
@ -19,36 +18,42 @@ import (
// @Security ApiKeyAuth // @Security ApiKeyAuth
// @Router /v1/pdfs/contracts [post] // @Router /v1/pdfs/contracts [post]
func (h *DefaultHandler) GenerateContract(c *fiber.Ctx) error { func (h *DefaultHandler) GenerateContract(c *fiber.Ctx) error {
logger := h.Logger.Named("GenerateContract")
contract := new(models.ContractRequest) contract := new(models.ContractRequest)
if err := c.BodyParser(contract); err != nil { if err := c.BodyParser(contract); err != nil {
logger.Errorw("Invalid request", "error", err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": err.Error(), "error": err.Error(),
}) })
} }
if !slices.Contains([]string{"en", "de"}, contract.Locale) { if !slices.Contains([]string{"en", "de"}, contract.Locale) {
logger.Errorw("Invalid locale", "locale", contract.Locale)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Invalid locale", "error": "Invalid locale",
}) })
} }
contract.Runners = repeatRunnerArrayItems(contract.Runners, 2) logger = logger.With("locale", contract.Locale)
templateString, err := h.StaticService.GetTemplate(contract.Locale, "contract") templateString, err := h.StaticService.GetTemplate(contract.Locale, "contract")
if err != nil { if err != nil {
log.Println(err) logger.Errorw("Template not found", "error", err)
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{ return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
"error": "Template not found", "error": "Template not found",
}) })
} }
template, err := h.Templater.StringToTemplate(templateString) template, err := h.Templater.StringToTemplate(templateString)
if err != nil { if err != nil {
logger.Errorw("Error parsing template", "error", err)
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": err.Error(), "error": err.Error(),
}) })
} }
genConfig := &models.ContractTemplateOptions{ genConfig := &models.ContractTemplateOptions{
Runners: contract.Runners, Runners: repeatRunnerArrayItems(contract.Runners, 2),
CurrencySymbol: h.Config.CurrencySymbol, CurrencySymbol: h.Config.CurrencySymbol,
Disclaimer: h.Config.SponosringDisclaimer, Disclaimer: h.Config.SponosringDisclaimer,
ReceiptMinimumAmount: h.Config.SponsoringReceiptMinimum, ReceiptMinimumAmount: h.Config.SponsoringReceiptMinimum,
@ -57,19 +62,23 @@ func (h *DefaultHandler) GenerateContract(c *fiber.Ctx) error {
BarcodePrefix: h.Config.SponsoringBarcodePrefix, BarcodePrefix: h.Config.SponsoringBarcodePrefix,
} }
logger.Info("Generating contract html")
result, err := h.Templater.Execute(template, genConfig) result, err := h.Templater.Execute(template, genConfig)
if err != nil { if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": err.Error(), "error": err.Error(),
}) })
} }
logger.Info("Generated contract html")
logger.Info("Converting html to pdf")
pdf, err := h.Converter.ToPdf(result, "a5", true) pdf, err := h.Converter.ToPdf(result, "a5", true)
if err != nil { if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": err.Error(), "error": err.Error(),
}) })
} }
logger.Info("Converted html to pdf")
c.Set(fiber.HeaderContentType, "application/pdf") c.Set(fiber.HeaderContentType, "application/pdf")
c.Set(fiber.HeaderContentDisposition, "attachment; filename=runner-contracts.pdf") c.Set(fiber.HeaderContentDisposition, "attachment; filename=runner-contracts.pdf")

View File

@ -4,6 +4,7 @@ import (
"git.odit.services/lfk/document-server/models" "git.odit.services/lfk/document-server/models"
"git.odit.services/lfk/document-server/services" "git.odit.services/lfk/document-server/services"
"github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2"
"go.uber.org/zap"
) )
type Handler interface { type Handler interface {
@ -19,4 +20,5 @@ type DefaultHandler struct {
Templater services.Templater Templater services.Templater
Converter services.Converter Converter services.Converter
StaticService services.StaticService StaticService services.StaticService
Logger *zap.SugaredLogger
} }

51
main.go
View File

@ -3,6 +3,8 @@ package main
import ( import (
"crypto/sha256" "crypto/sha256"
"crypto/subtle" "crypto/subtle"
"os"
"strings"
"git.odit.services/lfk/document-server/docs" // Correct import path for docs "git.odit.services/lfk/document-server/docs" // Correct import path for docs
"git.odit.services/lfk/document-server/handlers" "git.odit.services/lfk/document-server/handlers"
@ -16,6 +18,7 @@ import (
"github.com/redis/go-redis/v9" "github.com/redis/go-redis/v9"
"github.com/spf13/viper" "github.com/spf13/viper"
"go.uber.org/zap" "go.uber.org/zap"
"go.uber.org/zap/zapcore"
) )
var ( var (
@ -35,7 +38,8 @@ func validateAPIKey(c *fiber.Ctx, key string) (bool, error) {
func loadEnv() error { func loadEnv() error {
viper.SetDefault("PRODUCION", true) viper.SetDefault("LOGLEVEL", "INFO")
viper.SetDefault("PRODUCION", false)
viper.SetDefault("PORT", "3000") viper.SetDefault("PORT", "3000")
viper.SetDefault("APIKEY", "lfk") viper.SetDefault("APIKEY", "lfk")
viper.SetDefault("EVENTNAME", "Demo Event") viper.SetDefault("EVENTNAME", "Demo Event")
@ -67,7 +71,34 @@ func loadEnv() error {
return err return err
} }
logger.Infow("Loaded config", config) logger.Infow("Loaded config", "config", &config)
return nil
}
func initLogger() error {
logLevel := os.Getenv("LOGLEVEL")
if logLevel == "" {
logLevel = "INFO"
}
var zapLogLevel zapcore.Level
err := zapLogLevel.UnmarshalText([]byte(strings.ToLower(logLevel)))
if err != nil {
zapLogLevel = zapcore.InfoLevel
}
zapConfig := zap.NewProductionConfig()
zapConfig.Level = zap.NewAtomicLevelAt(zapLogLevel)
zapLogger, err := zapConfig.Build()
if err != nil {
return err
}
defer zapLogger.Sync()
logger = zapLogger.Sugar()
logger.Debug("Initialized logger")
return nil return nil
} }
@ -85,12 +116,12 @@ func loadEnv() error {
func main() { func main() {
// Init the logger // Init the logger
zapLogger, _ := zap.NewProduction() err := initLogger()
defer zapLogger.Sync() if err != nil {
logger = zapLogger.Sugar() return
logger.Info("Logger initialized") }
err := loadEnv() err = loadEnv()
if err != nil { if err != nil {
logger.Error(err) logger.Error(err)
return return
@ -98,7 +129,7 @@ func main() {
var redisClient *redis.Client var redisClient *redis.Client
if config.RedisAddr != "" { if config.RedisAddr != "" {
logger.Infow("Using redis", config.RedisAddr) logger.Infow("Using redis", "redisAddr", config.RedisAddr)
redisClient = redis.NewClient(&redis.Options{ redisClient = redis.NewClient(&redis.Options{
Addr: config.RedisAddr, Addr: config.RedisAddr,
}) })
@ -121,7 +152,9 @@ func main() {
Converter: &services.GotenbergConverter{ Converter: &services.GotenbergConverter{
BaseUrl: config.GotenbergBaseUrl, BaseUrl: config.GotenbergBaseUrl,
}, },
Logger: logger,
} }
logger.Debug("Initialized services")
// Create a new Fiber instance // Create a new Fiber instance
app := fiber.New(fiber.Config{ app := fiber.New(fiber.Config{
@ -147,9 +180,11 @@ func main() {
pdfv1.Post("/certificates", handler.GenerateCertificate) pdfv1.Post("/certificates", handler.GenerateCertificate)
v1.Get("/barcodes/:type/:content", handler.GenerateBarcode) v1.Get("/barcodes/:type/:content", handler.GenerateBarcode)
logger.Debug("Initialized routes")
app.Use(handler.NotFoundHandler) app.Use(handler.NotFoundHandler)
docs.SwaggerInfo.BasePath = "/" docs.SwaggerInfo.BasePath = "/"
logger.Infow("Starting server", "port", config.Port)
logger.Error(app.Listen("0.0.0.0:" + config.Port)) logger.Error(app.Listen("0.0.0.0:" + config.Port))
} }

View File

@ -1,6 +1,7 @@
package models package models
type Config struct { type Config struct {
LogLevel string `mapstructure:"LOGLEVEL"`
Prod bool `mapstructure:"PRODUCION"` Prod bool `mapstructure:"PRODUCION"`
Port string `mapstructure:"PORT"` Port string `mapstructure:"PORT"`
APIKey string `mapstructure:"APIKEY"` APIKey string `mapstructure:"APIKEY"`