From 368da6222c56e1a4049587028087d80387ec37dd Mon Sep 17 00:00:00 2001 From: Joshna Waikar Date: Tue, 3 Feb 2026 04:46:06 -0800 Subject: [PATCH] refactor: convert logging to structured zap logger --- cmd/laas/gen_external_ref_schema.go | 9 +-- pkg/auth/auth.go | 36 +++++++--- pkg/utils/util.go | 105 ++++++++++++++++++++-------- 3 files changed, 108 insertions(+), 42 deletions(-) diff --git a/cmd/laas/gen_external_ref_schema.go b/cmd/laas/gen_external_ref_schema.go index 571d746a..a05effa6 100644 --- a/cmd/laas/gen_external_ref_schema.go +++ b/cmd/laas/gen_external_ref_schema.go @@ -10,12 +10,13 @@ package main import ( "errors" "fmt" - "log" "os" "path/filepath" "github.com/dave/jennifer/jen" + logger "github.com/fossology/LicenseDb/pkg/log" + "go.uber.org/zap" "gopkg.in/yaml.v3" ) @@ -41,12 +42,12 @@ func main() { fieldsMetadata, err := os.ReadFile(PATH_EXTERNAL_REF_CONFIG_FILE) if err != nil { - log.Fatalf("Failed to instantiate json schema for external ref in license: %v", err) + logger.LogFatal("Failed to instantiate json schema for external ref in license", zap.Error(err)) } err = yaml.Unmarshal(fieldsMetadata, &externalRefFields) if err != nil { - log.Fatalf("Failed to instantiate json schema for external ref in license: %v", err) + logger.LogFatal("Failed to instantiate json schema for external ref in license", zap.Error(err)) } // REUSE-IgnoreStart @@ -74,7 +75,7 @@ func main() { err = fmt.Errorf("type %s in external_ref_fields.yaml is not supported", f.Type) } if err != nil { - log.Fatalf("Failed to instantiate json schema for external ref in license: %v", err) + logger.LogFatal("Failed to instantiate json schema for external ref in license", zap.Error(err)) return } field = field.Tag(map[string]string{"json": fmt.Sprintf("%s,omitempty", f.Name), "swaggerignore": "true"}) diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go index 68ccf762..231243e0 100644 --- a/pkg/auth/auth.go +++ b/pkg/auth/auth.go @@ -12,7 +12,6 @@ import ( "errors" "fmt" "html" - "log" "net/http" "os" "strconv" @@ -176,7 +175,9 @@ func CreateOidcUser(c *gin.Context) { Timestamp: time.Now().Format(time.RFC3339), } c.JSON(http.StatusInternalServerError, er) - log.Print("\033[31mError: OIDC environment variables not configured properly\033[0m") + logger.LogError( + "oidc environment variables not configured properly", + ) return } @@ -213,7 +214,11 @@ func CreateOidcUser(c *gin.Context) { keyset, err := Jwks.Lookup(context.Background(), os.Getenv("JWKS_URI")) if err != nil { - log.Print("\033[31mError: Failed jwk.Cache lookup from the oidc provider's URL\033[0m") + logger.LogError( + "failed jwk cache lookup from oidc provider", + zap.Error(err), + ) + er := models.LicenseError{ Status: http.StatusInternalServerError, Message: "Something went wrong", @@ -242,7 +247,10 @@ func CreateOidcUser(c *gin.Context) { } if keyError { - log.Printf("\033[31mError: Token verification failed due to invalid alg header key field \033[0m") + logger.LogError( + "token verification failed", + zap.String("reason", "invalid alg header key field"), + ) er := models.LicenseError{ Status: http.StatusUnauthorized, Message: "Please check your credentials and try again", @@ -263,12 +271,18 @@ func CreateOidcUser(c *gin.Context) { Timestamp: time.Now().Format(time.RFC3339), } c.JSON(http.StatusUnauthorized, er) - log.Printf("\033[31mError: Token verification failed \033[0m") + logger.LogError( + "token verification failed", + zap.String("stage", "jws_verify"), + ) return } - parsedToken, err := jwt.Parse([]byte(tokenString), jwt.WithValidate(true), jwt.WithVerify(false)) if err != nil { + logger.LogError( + "token parsing failed", + zap.Error(err), + ) er := models.LicenseError{ Status: http.StatusUnauthorized, Message: "Please check your credentials and try again", @@ -290,7 +304,10 @@ func CreateOidcUser(c *gin.Context) { Timestamp: time.Now().Format(time.RFC3339), } c.JSON(http.StatusUnauthorized, er) - log.Printf("\033[31mError: Issuer '%s' not supported\033[0m", iss) + logger.LogError( + "issuer not supported", + zap.String("issuer", iss), + ) return } @@ -313,7 +330,10 @@ func CreateOidcUser(c *gin.Context) { Timestamp: time.Now().Format(time.RFC3339), } c.JSON(http.StatusUnauthorized, er) - log.Printf("\033[31mError: %s\033[0m", errMessage) + logger.LogError( + "error occurred", + zap.String("message", errMessage), + ) return } level := "USER" diff --git a/pkg/utils/util.go b/pkg/utils/util.go index f01be78d..0eb9b4c3 100644 --- a/pkg/utils/util.go +++ b/pkg/utils/util.go @@ -12,7 +12,6 @@ import ( "encoding/json" "errors" "fmt" - "log" "net/http" "os" "reflect" @@ -28,8 +27,10 @@ import ( "github.com/gin-gonic/gin" "github.com/go-playground/validator/v10" "github.com/google/uuid" + "go.uber.org/zap" "github.com/fossology/LicenseDb/pkg/db" + logger "github.com/fossology/LicenseDb/pkg/log" "github.com/fossology/LicenseDb/pkg/models" "github.com/fossology/LicenseDb/pkg/validations" ) @@ -138,7 +139,6 @@ func InsertOrUpdateLicenseOnImport(lic *models.LicenseImportDTO, userId uuid.UUI return errors.New(message) } newLicense = license - if *oldLicense.Text != *newLicense.Text { if !*oldLicense.TextUpdatable { message = "Field `text_updatable` needs to be true to update the text" @@ -205,14 +205,19 @@ func InsertOrUpdateLicenseOnImport(lic *models.LicenseImportDTO, userId uuid.UUI } else if lic.Shortname != nil { erroredElem = *lic.Shortname } - red := "\033[31m" - reset := "\033[0m" - log.Printf("%s%s: %s%s", red, erroredElem, message, reset) + + logger.LogError( + "License import failed", + zap.String("license_id_or_shortname", erroredElem), + zap.String("message", message), + ) } else { - green := "\033[32m" - reset := "\033[0m" - log.Printf("%sImport for license '%s' successful%s", green, (*lic.Id).String(), reset) + logger.LogInfo( + "License import successful", + zap.String("license_id", (*lic.Id).String()), + ) } + return message, importStatus } @@ -306,8 +311,13 @@ func PerformObligationMapActions(tx *gorm.DB, userId uuid.UUID, obligation *mode return createObligationMapChangelog(tx, userId, newLicenseAssociations, oldLicenseAssociations, obligation) }); err != nil { + logger.LogError("Failed to update obligation-license mapping", + zap.String("obligation_id", obligation.Id.String()), + zap.Error(err), + ) errs = append(errs, err) } + return newLicenseAssociations, errs } @@ -501,33 +511,51 @@ func CreateObClassification(obClassification *models.ObligationClassification, u // Populatedb populates the database with license data from a JSON file. func Populatedb(datafile string) { var licenses []models.LicenseJson + // Read the content of the data file. byteResult, err := os.ReadFile(datafile) if err != nil { - log.Fatalf("Unable to read JSON file: %v", err) + logger.LogFatal("Unable to read JSON file", zap.Error(err)) + } + // Unmarshal the JSON file data into a slice of LicenseJson structs. if err := json.Unmarshal(byteResult, &licenses); err != nil { - log.Fatalf("error reading from json file: %v", err) + logger.LogFatal("Error unmarshalling JSON file", zap.Error(err)) } + // Fetch SUPER_ADMIN user user := models.User{} level := "SUPER_ADMIN" + if err := db.DB.Where(&models.User{UserLevel: &level}).First(&user).Error; err != nil { - log.Fatalf("Failed to find a super admin") + logger.LogFatal( + "Failed to find a super admin", + zap.String("level", level), + zap.Error(err), + ) + } for _, license := range licenses { result := license.Converter() + if err := validations.Validate.Struct(&result); err != nil { - red := "\033[31m" - reset := "\033[0m" - log.Printf("%s%s: %s%s", red, *result.Shortname, fmt.Sprintf("field '%s' failed validation: %s\n", err.(validator.ValidationErrors)[0].Field(), err.(validator.ValidationErrors)[0].Tag()), reset) + valErr := err.(validator.ValidationErrors)[0] + logger.LogError( + "License validation failed", + zap.String("shortname", *result.Shortname), + zap.String("field", valErr.Field()), + zap.String("tag", valErr.Tag()), + zap.Error(err), + ) continue } + _, _ = InsertOrUpdateLicenseOnImport(&result, user.Id) } + // Default obligation types DEFAULT_OBLIGATION_TYPES := []*models.ObligationType{ {Type: "OBLIGATION"}, {Type: "RISK"}, @@ -539,16 +567,20 @@ func Populatedb(datafile string) { err, status := CreateObType(obType, user.Id) if status == CREATED || status == CONFLICT { - green := "\033[32m" - reset := "\033[0m" - log.Printf("%s%s: %s%s", green, obType.Type, "Obligation type created successfully", reset) + logger.LogInfo( + "Obligation type created successfully", + zap.String("type", obType.Type), + ) } else { - red := "\033[31m" - reset := "\033[0m" - log.Printf("%s%s: %s%s", red, obType.Type, err.Error(), reset) + logger.LogError( + "Obligation type creation failed", + zap.String("type", obType.Type), + zap.Error(err), + ) } } + // Default obligation classifications DEFAULT_OBLIGATION_CLASSIFICATIONS := []*models.ObligationClassification{ {Classification: "GREEN", Color: "#00FF00"}, {Classification: "WHITE", Color: "#FFFFFF"}, @@ -560,13 +592,16 @@ func Populatedb(datafile string) { err, status := CreateObClassification(obClassification, user.Id) if status == CREATED || status == CONFLICT { - green := "\033[32m" - reset := "\033[0m" - log.Printf("%s%s: %s%s", green, obClassification.Classification, "Obligation classification created successfully", reset) + logger.LogInfo( + "Obligation classification created successfully", + zap.String("classification", obClassification.Classification), + ) } else { - red := "\033[31m" - reset := "\033[0m" - log.Printf("%s%s: %s%s", red, obClassification.Classification, err.Error(), reset) + logger.LogError( + "Obligation classification creation failed", + zap.String("classification", obClassification.Classification), + zap.Error(err), + ) } } } @@ -581,15 +616,23 @@ func SetSimilarityThreshold() { if parsed, err := strconv.ParseFloat(thresholdStr, 64); err == nil { threshold = parsed } else { - log.Printf("Invalid SIMILARITY_THRESHOLD '%s', using default %.1f", thresholdStr, defaultThreshold) + logger.LogWarn("Invalid SIMILARITY_THRESHOLD, using default", + zap.String("thresholdStr", thresholdStr), + zap.Float64("defaultThreshold", defaultThreshold), + ) } } else { - log.Printf("SIMILARITY_THRESHOLD not set, using default %.1f", defaultThreshold) + logger.LogInfo("SIMILARITY_THRESHOLD not set, using default", + zap.Float64("defaultThreshold", defaultThreshold), + ) } query := fmt.Sprintf("SET pg_trgm.similarity_threshold = %f", threshold) if err := db.DB.Exec(query).Error; err != nil { - log.Println("Failed to set similarity threshold:", err) + logger.LogError( + "Failed to set similarity threshold", + zap.Error(err), + ) } } @@ -664,7 +707,9 @@ func GetAuditEntity(c *gin.Context, audit *models.Audit) error { return err } default: - // no action + logger.LogWarn("Unknown audit type", + zap.String("type", audit.Type), + ) } return nil }