Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs/QuickStart.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,31 @@ This will:
- "PDF generation failed": Check HTML template validity
- "Storage error": Verify storage configuration and permissions

## Logger Setup
The `ILogger` interface present inside `/lib/logger.go` supports the following log levels:

- `Info`
- `Warn`
- `Error`
- `Debug`

Each method accepts:

- `ctx`: A `context.Context` for request-scoped logging or tracing
- `msg`: Log message string
- `fields`: Key-value pairs for structured logging

#### Setting Up Logger

1. Implement the `ILogger` interface using your preferred logger.
2. Call `log.Initialize(yourLoggerInstance)` inside `/service/main.go`
3. Use `log.Logger.Info()`, `log.Logger.Error()`, etc., throughout your code.

#### Example: Using Zerolog
A sample implementation of ILogger interface can be found at `/service/utils/zerolog.go` and initialized in `service/main.go`

<br>

## Next Steps

- Check the API documentation for more endpoints
Expand Down
6 changes: 4 additions & 2 deletions lib/browser_manager/initialize.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"os"

log "github.com/Zomato/espresso/lib/logger"
"github.com/go-rod/rod"
"github.com/go-rod/rod/lib/launcher"
)
Expand All @@ -14,7 +15,8 @@ var (
)

func Init(ctx context.Context, tabPool int) error {
fmt.Println("Initializing browser...")
log.Logger.Info(ctx, "Initializing Browser...", nil)

browserPath := os.Getenv("ROD_BROWSER_BIN")
if browserPath == "" {
return fmt.Errorf("ROD_BROWSER_BIN environment variable not set")
Expand Down Expand Up @@ -82,7 +84,7 @@ func Init(ctx context.Context, tabPool int) error {
}
Browser = browser

fmt.Println("Browser connected successfully")
log.Logger.Info(ctx, "Browser Connected Successfully", nil)

InitializeTabManager(ctx, tabPool)

Expand Down
10 changes: 7 additions & 3 deletions lib/browser_manager/tabManager.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"sync"

log "github.com/Zomato/espresso/lib/logger"
"github.com/go-rod/rod"
)

Expand All @@ -25,7 +26,9 @@ func InitializeTabManager(ctx context.Context, tabPool int) {
}

func NewTabPool(ctx context.Context, browser *rod.Browser, tabPool int) *TabPool {
fmt.Println("Initializing tab pool with ", tabPool, " tabs")

log.Logger.Info(ctx, "Initializing tab pool", map[string]any{"totalTabs": tabPool})

numTabs = tabPool
if tabPool == 0 {
return nil
Expand All @@ -48,7 +51,8 @@ func NewTabPool(ctx context.Context, browser *rod.Browser, tabPool int) *TabPool

// if the `browser.tabs` is 0 then we are creating a new tab on each request
func GetTab() *rod.Page {
fmt.Println("Getting tab")
log.Logger.Info(context.Background(), "Getting tab", nil)

if numTabs == 0 {
return Browser.MustPage("about:blank")
}
Expand All @@ -58,7 +62,7 @@ func GetTab() *rod.Page {
}

func ReleaseTab(page *rod.Page) {
fmt.Println("Releasing tab")
log.Logger.Info(context.Background(), "Releasing Tab", nil)
if numTabs == 0 {
page.MustClose()
return
Expand Down
2 changes: 0 additions & 2 deletions lib/certmanager/certmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ func LoadSigningCredentials(ctx context.Context, certConfig *CertificateConfig)
}

func getCertificate(certPath string) (*x509.Certificate, error) {

certBytes, err := os.ReadFile(certPath)
if err != nil {
return nil, fmt.Errorf("failed to read certificate file: %v", err)
Expand All @@ -63,7 +62,6 @@ func getCertificate(certPath string) (*x509.Certificate, error) {
}

func getKey(keyPath, password string) (crypto.Signer, error) {

keyBytes, err := os.ReadFile(keyPath)
if err != nil {
return nil, fmt.Errorf("failed to read private key file: %v", err)
Expand Down
33 changes: 33 additions & 0 deletions lib/logger/logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package log

import (
"context"
)

var (

// Assigning default no-op logger. Later it will be replaced by actual logger(if provided) inside init function.
Logger ILogger = newNoOpLogger()
)

type Level uint8

const (
DebugLevel Level = iota
Info
Warn
Error
)

type Fields map[string]any

type ILogger interface {
Info(ctx context.Context, msg string, fields Fields)
Warn(ctx context.Context, msg string, fields Fields)
Error(ctx context.Context, msg string, err error, fields Fields)
Debug(ctx context.Context, msg string, fields Fields)
}

func Initialize(loggerInstance ILogger) {
Logger = loggerInstance
}
23 changes: 23 additions & 0 deletions lib/logger/no-op.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
Default no operation logger for no overhead. It is assigned default to ILogger instance in logger.go file.
*/

package log

import (
"context"
)

type NoOpLogger struct{}

func newNoOpLogger() NoOpLogger {
return NoOpLogger{}
}

func (n NoOpLogger) Info(ctx context.Context, msg string, fields Fields) {}

func (n NoOpLogger) Warn(ctx context.Context, msg string, fields Fields) {}

func (n NoOpLogger) Error(ctx context.Context, msg string, err error, fields Fields) {}

func (n NoOpLogger) Debug(ctx context.Context, msg string, fields Fields) {}
21 changes: 12 additions & 9 deletions lib/renderer/pdf.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"time"

"github.com/Zomato/espresso/lib/browser_manager"
log "github.com/Zomato/espresso/lib/logger"
"github.com/Zomato/espresso/lib/templatestore"
"github.com/go-rod/rod"
)
Expand All @@ -20,7 +21,9 @@ func GetHtmlPdf(ctx context.Context, params *GetHtmlPdfInput, storeAdapter *temp
}

duration := time.Since(startTime)
fmt.Println("starting template parsing at :: ", duration)

log.Logger.Info(ctx, "starting template parsing at", map[string]any{"time": duration})

var err error
var templateFile *template.Template
if storeAdapter != nil {
Expand All @@ -40,7 +43,7 @@ func GetHtmlPdf(ctx context.Context, params *GetHtmlPdfInput, storeAdapter *temp
}

duration = time.Since(startTime)
fmt.Println("starting unmarshaling data at :: ", duration)
log.Logger.Info(ctx, "starting unmarshaling data at", map[string]any{"time": duration})

data := params.Data

Expand All @@ -57,16 +60,16 @@ func GetHtmlPdf(ctx context.Context, params *GetHtmlPdfInput, storeAdapter *temp
page := browser_manager.GetTab()
defer func() {
duration = time.Since(startTime)
fmt.Println("closing tab at :: ", duration)
log.Logger.Info(ctx, "closing tab at", map[string]any{"time": duration})
browser_manager.ReleaseTab(page)
}()

duration = time.Since(startTime)
fmt.Println("prefetching images at :: ", duration)
log.Logger.Info(ctx, "prefetching images at", map[string]any{"time": duration})
unmarshaledData = PrefetchImages(ctx, unmarshaledData)

duration = time.Since(startTime)
fmt.Println("unmarshaled data & started template execution at :: ", duration)
log.Logger.Info(ctx, "unmarshaled data & started template execution at", map[string]any{"time": duration})

htmlContent, err := ExecuteTemplate(ctx, templateFile, unmarshaledData)
if err != nil {
Expand All @@ -76,7 +79,7 @@ func GetHtmlPdf(ctx context.Context, params *GetHtmlPdfInput, storeAdapter *temp
htmlContent = AddImagesFromMetaData(ctx, htmlContent, unmarshaledData)

duration = time.Since(startTime)
fmt.Println("template executed and requesting new tab at :: ", duration)
log.Logger.Info(ctx, "template executed and requesting new tab at", map[string]any{"time": duration})

if params.IsSinglePage {
page.MustSetViewport(794, 1124, 1.0, false)
Expand All @@ -86,7 +89,7 @@ func GetHtmlPdf(ctx context.Context, params *GetHtmlPdfInput, storeAdapter *temp
}

duration = time.Since(startTime)
fmt.Println("rendering data in new tab at :: ", duration)
log.Logger.Info(ctx, "rendering data in new tab at", map[string]any{"time": duration})

err = page.SetDocumentContent(string(htmlContent))
if err != nil {
Expand Down Expand Up @@ -120,15 +123,15 @@ func GetHtmlPdf(ctx context.Context, params *GetHtmlPdfInput, storeAdapter *temp
}

duration = time.Since(startTime)
fmt.Println("generating pdf at :: ", duration)
log.Logger.Info(ctx, "generating pdf at", map[string]any{"time": duration})

pdfStream, err := page.PDF(pdfParams)
if err != nil {
return nil, fmt.Errorf("unable to generate pdf: %v", err)
}

duration = time.Since(startTime)
fmt.Println("pdf generated at :: ", duration)
log.Logger.Info(ctx, "pdf generated at", map[string]any{"time": duration})

return pdfStream, nil
}
Expand Down
29 changes: 17 additions & 12 deletions lib/renderer/prefetchImages.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"sync"
"time"

log "github.com/Zomato/espresso/lib/logger"
"github.com/Zomato/espresso/lib/workerpool"
)

Expand Down Expand Up @@ -45,39 +46,42 @@ func PrefetchImages(ctx context.Context, data map[string]interface{}) map[string
wg.Done()
if r := recover(); r != nil {
err := fmt.Errorf("panic: %v and stacktrace %s", r, string(debug.Stack()))
fmt.Println("Recovered from panic: ", err)
log.Logger.Info(ctx, "recovered from panic", map[string]any{"error": err})

}
}()
var dataURI string
var err error
if strings.HasPrefix(v, "https://") {
duration := time.Since(startTime)
fmt.Printf("fetching %s image at :: %s\n", v, duration)
log.Logger.Info(ctx, "fetching image at", map[string]any{"name": v, "time": duration})

dataURI, err = fetchImageAsDataURIFromURL(v)
if err != nil {
fmt.Printf("failed to download image for key %s: %v\n", k, err)
log.Logger.Error(ctx, "failed to download image", err, map[string]any{"key": k})
return
}
}

if dataURI == "" {
fmt.Printf("failed to download image for key %s: dataURI is empty\n", k)
log.Logger.Error(ctx, "failed to download image. data uri is empty", nil, map[string]any{"key": k})

mu.Lock()
parentData[k] = ""
mu.Unlock()
return
}

duration := time.Since(startTime)
fmt.Printf("fetched %s image data at :: %s\n", v, duration)
log.Logger.Info(ctx, "fetched image data at", map[string]any{"time": duration, "image": v})

mu.Lock()
parentData[k] = dataURI
mu.Unlock()
fmt.Printf("replaced image data for key %s at :: %s, error :: %v\n", k, duration, err)
log.Logger.Info(ctx, "replaced image data at", map[string]any{"time": duration, "key": k, "error": err})
}, key, strValue, current.data)
if err != nil {
fmt.Printf("failed to submit task to worker pool: %v\n", err)
log.Logger.Error(ctx, "failed to submit task to worker pool", err, nil)
}
} else if nestedMap, ok := value.(map[string]interface{}); ok {
stack = append(stack, stackItem{key: key, data: nestedMap})
Expand All @@ -94,12 +98,12 @@ func PrefetchImages(ctx context.Context, data map[string]interface{}) map[string
}

duration := time.Since(startTime)
fmt.Println("prefetching images completed at :: ", duration)
log.Logger.Info(ctx, "prefetching images completed at", map[string]any{"time": duration})

wg.Wait()

duration = time.Since(startTime)
fmt.Println("all worker pool tasks completed at :: ", duration)
log.Logger.Info(ctx, "all worker pool tasks completed at", map[string]any{"time": duration})

return data
}
Expand All @@ -109,15 +113,15 @@ func fetchImageAsDataURIFromURL(url string) (string, error) {
startTime := time.Now()

duration := time.Since(startTime)
fmt.Printf("fetching %s image at :: %s\n", url, duration)
log.Logger.Info(context.Background(), "fetching image at", map[string]any{"time": duration, "url": url})

resp, err := http.Get(url)
if err != nil {
return "", fmt.Errorf("failed to fetch image: %v", err)
}

duration = time.Since(startTime)
fmt.Printf("fetched %s image data at :: %s\n", url, duration)
log.Logger.Info(context.Background(), "fetched image at", map[string]any{"time": duration, "url": url})

defer resp.Body.Close()

Expand All @@ -140,6 +144,7 @@ func fetchImageAsDataURIFromURL(url string) (string, error) {
dataURI := fmt.Sprintf("data:%s;base64,%s", contentType, base64.StdEncoding.EncodeToString(imageBytes))

duration = time.Since(startTime)
fmt.Printf("returning %s image data at :: %s\n", url, duration)
log.Logger.Info(context.Background(), "returning image at", map[string]any{"time": duration, "url": url})

return dataURI, nil
}
1 change: 1 addition & 0 deletions lib/signer/appearance.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ func (context *SignContext) createIncPageUpdate(pageNumber, annot uint32) ([]byt
}

func (context *SignContext) createAppearance(rect [4]float64) ([]byte, error) {

text := context.SignData.Signature.Info.Name

rectWidth := rect[2] - rect[0]
Expand Down
1 change: 1 addition & 0 deletions lib/signer/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
)

func (context *SignContext) addObject(object []byte) (uint32, error) {

if context.lastXrefID == 0 {
lastXrefID, err := context.getLastObjectIDFromXref()
if err != nil {
Expand Down
Loading