feat(services): Logging
This commit is contained in:
parent
4d57cf827d
commit
11ea0858bb
8
main.go
8
main.go
@ -137,9 +137,11 @@ func main() {
|
|||||||
|
|
||||||
barcodeGenerator := &services.DefaultBarcodeService{
|
barcodeGenerator := &services.DefaultBarcodeService{
|
||||||
RedisClient: redisClient,
|
RedisClient: redisClient,
|
||||||
|
Logger: logger.Named("DefaultBarcodeService"),
|
||||||
}
|
}
|
||||||
staticService := &services.DefaultStaticService{
|
staticService := &services.DefaultStaticService{
|
||||||
Cache: make(map[string]string),
|
Cache: make(map[string]string),
|
||||||
|
Logger: logger.Named("DefaultStaticService"),
|
||||||
}
|
}
|
||||||
handler := handlers.DefaultHandler{
|
handler := handlers.DefaultHandler{
|
||||||
Config: config,
|
Config: config,
|
||||||
@ -148,11 +150,13 @@ func main() {
|
|||||||
Templater: &services.DefaultTemplater{
|
Templater: &services.DefaultTemplater{
|
||||||
BarcodeService: barcodeGenerator,
|
BarcodeService: barcodeGenerator,
|
||||||
StaticService: staticService,
|
StaticService: staticService,
|
||||||
|
Logger: logger.Named("DefaultTemplater"),
|
||||||
},
|
},
|
||||||
Converter: &services.GotenbergConverter{
|
Converter: &services.GotenbergConverter{
|
||||||
BaseUrl: config.GotenbergBaseUrl,
|
BaseUrl: config.GotenbergBaseUrl,
|
||||||
|
Logger: logger.Named("GotenbergConverter"),
|
||||||
},
|
},
|
||||||
Logger: logger,
|
Logger: logger.Named("DefaultHandler"),
|
||||||
}
|
}
|
||||||
logger.Debug("Initialized services")
|
logger.Debug("Initialized services")
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ import (
|
|||||||
"image/color"
|
"image/color"
|
||||||
"image/draw"
|
"image/draw"
|
||||||
"image/png"
|
"image/png"
|
||||||
"log"
|
|
||||||
"slices"
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -17,6 +16,7 @@ import (
|
|||||||
"github.com/boombuler/barcode/ean"
|
"github.com/boombuler/barcode/ean"
|
||||||
"github.com/boombuler/barcode/qr"
|
"github.com/boombuler/barcode/qr"
|
||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BarcodeService interface {
|
type BarcodeService interface {
|
||||||
@ -26,19 +26,26 @@ type BarcodeService interface {
|
|||||||
|
|
||||||
type DefaultBarcodeService struct {
|
type DefaultBarcodeService struct {
|
||||||
RedisClient *redis.Client
|
RedisClient *redis.Client
|
||||||
|
Logger *zap.SugaredLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *DefaultBarcodeService) GenerateBarcode(format string, content string, width int, height int, padding int) (bytes.Buffer, error) {
|
func (b *DefaultBarcodeService) GenerateBarcode(format string, content string, width int, height int, padding int) (bytes.Buffer, error) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
logger := b.Logger.Named("GenerateBarcode")
|
||||||
|
|
||||||
if !b.IsTypeSupported(format) {
|
if !b.IsTypeSupported(format) {
|
||||||
|
logger.Errorw("Unsupported barcode type", "type", format)
|
||||||
return bytes.Buffer{}, fmt.Errorf("unsupported barcode type: %s", format)
|
return bytes.Buffer{}, fmt.Errorf("unsupported barcode type: %s", format)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger = logger.With("type", format, "content", content, "width", width, "height", height, "padding", padding)
|
||||||
|
cacheKey := fmt.Sprintf("barcode:%s:%s:%d:%d:%d", format, content, width, height, padding)
|
||||||
|
|
||||||
if b.RedisClient != nil {
|
if b.RedisClient != nil {
|
||||||
cachedBarcode, err := b.RedisClient.Get(ctx, fmt.Sprintf("barcode:%s:%s:%d:%d:%d", format, content, width, height, padding)).Result()
|
logger.Debugw("Checking cache for barcode", "key", cacheKey)
|
||||||
|
cachedBarcode, err := b.RedisClient.Get(ctx, cacheKey).Result()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Printf("Cache hit for barcode:%s:%s:%d:%d", format, content, width, height)
|
logger.Infow("Barcode found in cache", "key", cacheKey)
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
buf.Write([]byte(cachedBarcode))
|
buf.Write([]byte(cachedBarcode))
|
||||||
return buf, nil
|
return buf, nil
|
||||||
@ -73,6 +80,7 @@ func (b *DefaultBarcodeService) GenerateBarcode(format string, content string, w
|
|||||||
bg := image.NewRGBA(image.Rect(0, 0, width, height))
|
bg := image.NewRGBA(image.Rect(0, 0, width, height))
|
||||||
white := color.RGBA{255, 255, 255, 255}
|
white := color.RGBA{255, 255, 255, 255}
|
||||||
draw.Draw(bg, bg.Bounds(), &image.Uniform{white}, image.Point{}, draw.Src)
|
draw.Draw(bg, bg.Bounds(), &image.Uniform{white}, image.Point{}, draw.Src)
|
||||||
|
logger.Debug("Created white background")
|
||||||
|
|
||||||
// Calculate the new size for the barcode to fit within the padding
|
// Calculate the new size for the barcode to fit within the padding
|
||||||
newWidth := width - 2*padding
|
newWidth := width - 2*padding
|
||||||
@ -81,24 +89,32 @@ func (b *DefaultBarcodeService) GenerateBarcode(format string, content string, w
|
|||||||
// Scale the barcode to the new size
|
// Scale the barcode to the new size
|
||||||
scaledCode, err := barcode.Scale(generatedCode, newWidth, newHeight)
|
scaledCode, err := barcode.Scale(generatedCode, newWidth, newHeight)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to scale barcode", "error", err)
|
||||||
return bytes.Buffer{}, err
|
return bytes.Buffer{}, err
|
||||||
}
|
}
|
||||||
|
logger.Debug("Scaled barcode")
|
||||||
|
|
||||||
// Draw the barcode on top of the white background with padding
|
// Draw the barcode on top of the white background with padding
|
||||||
draw.Draw(bg, scaledCode.Bounds().Add(image.Point{padding, padding}), scaledCode, image.Point{}, draw.Over)
|
draw.Draw(bg, scaledCode.Bounds().Add(image.Point{padding, padding}), scaledCode, image.Point{}, draw.Over)
|
||||||
|
logger.Debug("Drew barcode on background")
|
||||||
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
err = png.Encode(&buf, bg)
|
err = png.Encode(&buf, bg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to encode barcode to PNG", "error", err)
|
||||||
return bytes.Buffer{}, err
|
return bytes.Buffer{}, err
|
||||||
}
|
}
|
||||||
|
logger.Debug("Encoded barcode to PNG")
|
||||||
|
|
||||||
if b.RedisClient != nil {
|
if b.RedisClient != nil {
|
||||||
err = b.RedisClient.Set(ctx, fmt.Sprintf("barcode:%s:%s:%d:%d", format, content, width, height), buf.String(), 10*time.Minute).Err()
|
err = b.RedisClient.Set(ctx, cacheKey, buf.String(), 10*time.Minute).Err()
|
||||||
|
logger.Debugw("Cached barcode", "key", cacheKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to cache barcode", "error", err)
|
||||||
return bytes.Buffer{}, err
|
return bytes.Buffer{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
logger.Info("Generated barcode")
|
||||||
|
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/oxplot/papersizes"
|
"github.com/oxplot/papersizes"
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Converter interface {
|
type Converter interface {
|
||||||
@ -16,92 +17,115 @@ type Converter interface {
|
|||||||
|
|
||||||
type GotenbergConverter struct {
|
type GotenbergConverter struct {
|
||||||
BaseUrl string
|
BaseUrl string
|
||||||
|
Logger *zap.SugaredLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GotenbergConverter) ToPdf(html string, pageSize string, landscape bool) ([]byte, error) {
|
func (g *GotenbergConverter) ToPdf(html string, pageSize string, landscape bool) ([]byte, error) {
|
||||||
|
logger := g.Logger.Named("ToPdf").With("page_size", pageSize, "landscape", landscape, "base_url", g.BaseUrl)
|
||||||
|
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
defer client.CloseIdleConnections()
|
defer client.CloseIdleConnections()
|
||||||
|
logger.Debug("Created HTTP client")
|
||||||
|
|
||||||
body := &bytes.Buffer{}
|
body := &bytes.Buffer{}
|
||||||
writer := multipart.NewWriter(body)
|
writer := multipart.NewWriter(body)
|
||||||
|
|
||||||
part, err := writer.CreateFormFile("files", "index.html")
|
part, err := writer.CreateFormFile("files", "index.html")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to create form file", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = part.Write([]byte(html))
|
_, err = part.Write([]byte(html))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to write to form file", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
size := papersizes.FromName(pageSize)
|
size := papersizes.FromName(pageSize)
|
||||||
if size == nil {
|
if size == nil {
|
||||||
|
logger.Errorw("Invalid page size", "size", pageSize)
|
||||||
return nil, fmt.Errorf("invalid page size: %s", pageSize)
|
return nil, fmt.Errorf("invalid page size: %s", pageSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writer.WriteField("paperWidth", strconv.Itoa(size.Width)+"mm")
|
err = writer.WriteField("paperWidth", strconv.Itoa(size.Width)+"mm")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to write paper width", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writer.WriteField("paperHeight", strconv.Itoa(size.Height)+"mm")
|
err = writer.WriteField("paperHeight", strconv.Itoa(size.Height)+"mm")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to write paper height", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writer.WriteField("landscape", strconv.FormatBool(landscape))
|
err = writer.WriteField("landscape", strconv.FormatBool(landscape))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to write landscape", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writer.WriteField("marginTop", "0")
|
err = writer.WriteField("marginTop", "0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to write margin top", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writer.WriteField("marginBottom", "0")
|
err = writer.WriteField("marginBottom", "0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to write margin bottom", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writer.WriteField("marginLeft", "0")
|
err = writer.WriteField("marginLeft", "0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to write margin left", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writer.WriteField("marginRight", "0")
|
err = writer.WriteField("marginRight", "0")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to write margin right", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writer.WriteField("preferCssPageSize", "true")
|
err = writer.WriteField("preferCssPageSize", "true")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to write prefer css page size", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = writer.Close()
|
err = writer.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to close writer", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
logger.Debug("Created form data")
|
||||||
|
|
||||||
|
logger.Debug("Creating HTTP request")
|
||||||
req, err := http.NewRequest("POST", g.BaseUrl+"/forms/chromium/convert/html", body)
|
req, err := http.NewRequest("POST", g.BaseUrl+"/forms/chromium/convert/html", body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||||
|
|
||||||
|
logger.Debug("Sending HTTP request")
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to send request", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
logger.Debug("Received HTTP response")
|
||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
data := new(bytes.Buffer)
|
data := new(bytes.Buffer)
|
||||||
_, err = data.ReadFrom(resp.Body)
|
_, err = data.ReadFrom(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to read response body", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.Debug("Returning PDF data")
|
||||||
return data.Bytes(), nil
|
return data.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Templater interface {
|
type Templater interface {
|
||||||
@ -17,6 +19,7 @@ type Templater interface {
|
|||||||
type DefaultTemplater struct {
|
type DefaultTemplater struct {
|
||||||
BarcodeService BarcodeService
|
BarcodeService BarcodeService
|
||||||
StaticService StaticService
|
StaticService StaticService
|
||||||
|
Logger *zap.SugaredLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
func idToEan13(id string, prefix string) (string, error) {
|
func idToEan13(id string, prefix string) (string, error) {
|
||||||
@ -48,10 +51,13 @@ func (t *DefaultTemplater) GenerateBarcode(code string, format string, prefix st
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *DefaultTemplater) SelectSponsorImage(id int) (string, error) {
|
func (t *DefaultTemplater) SelectSponsorImage(id int) (string, error) {
|
||||||
|
logger := t.Logger.Named("SelectSponsorImage")
|
||||||
sponsors, err := t.StaticService.ListFilesInStaticSubFolder("images/sponsors")
|
sponsors, err := t.StaticService.ListFilesInStaticSubFolder("images/sponsors")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Errorw("Failed to list sponsors", "error", err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
logger.Debugw("Selected sponsor", "sponsors", sponsors, "id", id, "selected", sponsors[id%len(sponsors)])
|
||||||
return t.StaticService.GetImage("sponsors/" + strings.TrimSuffix(sponsors[id%len(sponsors)], ".base64")), nil
|
return t.StaticService.GetImage("sponsors/" + strings.TrimSuffix(sponsors[id%len(sponsors)], ".base64")), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,8 +3,9 @@ package services
|
|||||||
import (
|
import (
|
||||||
_ "embed"
|
_ "embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
type StaticService interface {
|
type StaticService interface {
|
||||||
@ -14,47 +15,55 @@ type StaticService interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DefaultStaticService struct {
|
type DefaultStaticService struct {
|
||||||
Cache map[string]string
|
Cache map[string]string
|
||||||
|
Logger *zap.SugaredLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultStaticService) GetTemplate(locale, templateName string) (string, error) {
|
func (s *DefaultStaticService) GetTemplate(locale, templateName string) (string, error) {
|
||||||
|
logger := s.Logger.Named("GetTemplate").With("locale", locale, "template_name", templateName)
|
||||||
|
|
||||||
if s.Cache[locale+templateName] != "" {
|
if s.Cache[locale+templateName] != "" {
|
||||||
log.Printf("returning cached template %s with locale %s", templateName, locale)
|
logger.Debugw("Template found in cache", "key", locale+templateName)
|
||||||
return s.Cache[locale+templateName], nil
|
return s.Cache[locale+templateName], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
content, err := os.ReadFile(fmt.Sprintf("static/templates/%s/%s.html", templateName, locale))
|
content, err := os.ReadFile(fmt.Sprintf("static/templates/%s/%s.html", templateName, locale))
|
||||||
if content == nil || err != nil {
|
if content == nil || err != nil {
|
||||||
log.Printf("error reading template %s with locale %s: %v", templateName, locale, err)
|
logger.Errorw("Failed to read template", "error", err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.Cache[locale+templateName] = string(content)
|
s.Cache[locale+templateName] = string(content)
|
||||||
|
logger.Debugw("Saved template to cache", "key", locale+templateName)
|
||||||
|
|
||||||
return string(content), nil
|
return string(content), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultStaticService) ListFilesInStaticSubFolder(folderName string) ([]string, error) {
|
func (s *DefaultStaticService) ListFilesInStaticSubFolder(folderName string) ([]string, error) {
|
||||||
|
logger := s.Logger.Named("ListFilesInStaticSubFolder").With("folder_name", folderName)
|
||||||
|
|
||||||
files, err := os.ReadDir(fmt.Sprintf("static/%s", folderName))
|
files, err := os.ReadDir(fmt.Sprintf("static/%s", folderName))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error reading files from folder %s: %v", folderName, err)
|
logger.Errorw("Failed to list files", "error", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var images []string
|
var images []string
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
if file.IsDir() {
|
if file.IsDir() {
|
||||||
continue
|
logger.Debugw("Skipping directory", "file", file.Name())
|
||||||
}
|
}
|
||||||
images = append(images, file.Name())
|
images = append(images, file.Name())
|
||||||
}
|
}
|
||||||
|
logger.Debugw("Listed files", "files", images)
|
||||||
return images, nil
|
return images, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *DefaultStaticService) GetImage(imageName string) string {
|
func (s *DefaultStaticService) GetImage(imageName string) string {
|
||||||
|
logger := s.Logger.Named("GetImage").With("image_name", imageName)
|
||||||
|
|
||||||
content, err := os.ReadFile("static/images/" + imageName + ".base64")
|
content, err := os.ReadFile("static/images/" + imageName + ".base64")
|
||||||
if content == nil || err != nil {
|
if content == nil || err != nil {
|
||||||
log.Printf("error reading image %s: %v", imageName, err)
|
logger.Errorw("Failed to read image", "error", err)
|
||||||
return ImageErrorBase64
|
return ImageErrorBase64
|
||||||
}
|
}
|
||||||
return string(content)
|
return string(content)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user