From b77a8857e60b2f6cf5db5439dd3394ff732170f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dalibor=20Markovi=C4=87?= Date: Fri, 12 Jun 2026 22:33:42 +0200 Subject: [PATCH] refactor(log): prelazak sa log na log/slog (strukturisano logovanje) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Uveden podrazumevani slog logger u main.go (podesiLog): JSON u produkciji, tekst u razvoju, nivo Info. Svih ~70 poziva log.Printf/Println/Fatalf zamenjeno slog.Error/Warn/Info: greška se prosleđuje kao atribut "error", informativne vrednosti kao imenovani atributi (port, broj, putanja...), Fatalf -> Error + os.Exit(1). Upozorenja (inicijalizacija/čišćenje dozvola, migracija kolone) idu kao slog.Warn. Auth log (internal/auth/log.go) namerno NIJE diran — ostaje zaseban *log.Logger u fail2ban formatu. (slog.SetDefault usput preusmerava i standardni log paket.) --- cmd/ntech/main.go | 50 +++++++++++++++++++++------------ internal/config/setup.go | 7 +++-- internal/db/sqlite/migracije.go | 4 +-- internal/handler/dashboard.go | 18 ++++++------ internal/handler/izvestaji.go | 12 ++++---- internal/handler/kes.go | 14 ++++----- internal/handler/klijent.go | 6 ++-- internal/handler/podesavanja.go | 32 ++++++++++----------- internal/handler/podsetnici.go | 6 ++-- internal/handler/prodaja.go | 8 +++--- internal/handler/profil.go | 12 ++++---- internal/handler/servis.go | 14 ++++----- 12 files changed, 99 insertions(+), 84 deletions(-) diff --git a/cmd/ntech/main.go b/cmd/ntech/main.go index c878b5f..814320b 100644 --- a/cmd/ntech/main.go +++ b/cmd/ntech/main.go @@ -7,7 +7,7 @@ import ( "encoding/base64" "fmt" "io/fs" - "log" + "log/slog" "net/http" "os" "mime" @@ -31,10 +31,24 @@ import ( // Verzija se postavlja pri produkcijskom buildu: go build -ldflags "-X main.Verzija=1.2.0" var Verzija = "dev" +// podesiLog postavlja podrazumevani slog logger: JSON u produkciji (za mašinsku +// obradu logova), tekst u razvoju (čitljivije). Nivo je Info. +func podesiLog() { + opcije := &slog.HandlerOptions{Level: slog.LevelInfo} + var handler slog.Handler + if os.Getenv("NTECH_ENV") == "production" { + handler = slog.NewJSONHandler(os.Stdout, opcije) + } else { + handler = slog.NewTextHandler(os.Stdout, opcije) + } + slog.SetDefault(slog.New(handler)) +} + func main() { mime.AddExtensionType(".js", "text/javascript") mime.AddExtensionType(".css", "text/css") godotenv.Load("ntech.env") + podesiLog() auth.InitAuthLog() // disk-first logika: ako folder postoji pored binarnog fajla — koristi disk, inače embed. @@ -73,38 +87,38 @@ func main() { db, err := sqlite.OtvoriDB(putanjaBaze) if err != nil { - log.Fatalf("Greška pri otvaranju baze: %v", err) + slog.Error("Greška pri otvaranju baze", "error", err); os.Exit(1) } defer db.Close() if err := sqlite.PokreniMigracije(db, migrFS); err != nil { - log.Fatalf("Greška pri migracijama: %v", err) + slog.Error("Greška pri migracijama", "error", err); os.Exit(1) } - log.Println("Migracije uspešno izvršene") + slog.Info("migracije uspešno izvršene") // popuni tabelu dozvola podrazumevanim vrednostima ako je prazna if err := sqlite.InicijalizujDozvole(context.Background(), db, ntechmw.ImaDozvolu, ntechmw.SveAkcije()); err != nil { - log.Printf("Upozorenje: greška pri inicijalizaciji dozvola: %v", err) + slog.Warn("greška pri inicijalizaciji dozvola", "error", err) } // ukloni zastarele dozvole (siročiće) koje više ne postoje u kodu if br, err := sqlite.OcistiSirociceDoz(context.Background(), db, ntechmw.SveAkcije()); err != nil { - log.Printf("Upozorenje: greška pri čišćenju dozvola: %v", err) + slog.Warn("greška pri čišćenju dozvola", "error", err) } else if br > 0 { - log.Printf("Dozvole: uklonjeno %d zastarelih redova", br) + slog.Info("uklonjene zastarele dozvole", "broj", br) } // ključ za šifrovanje TOTP tajni u mirovanju (AES-256-GCM) totpKljuc, err := ucitajTotpKljuc() if err != nil { - log.Fatalf("Greška pri učitavanju ključa za TOTP: %v", err) + slog.Error("Greška pri učitavanju ključa za TOTP", "error", err); os.Exit(1) } // jednokratno šifruj eventualne stare TOTP tajne koje su ostale kao čist tekst if br, err := sqlite.ZasifrujPostojeceTotp(context.Background(), db, totpKljuc); err != nil { - log.Printf("Upozorenje: greška pri šifrovanju postojećih TOTP tajni: %v", err) + slog.Warn("greška pri šifrovanju postojećih TOTP tajni", "error", err) } else if br > 0 { - log.Printf("TOTP: šifrovano %d postojećih tajni", br) + slog.Info("šifrovane postojeće TOTP tajne", "broj", br) } napraviBackup(db, putanjaBaze) @@ -123,10 +137,10 @@ func main() { if os.Getenv("NTECH_ENV") == "production" { kes, err := handler.KreirajKes(templFS) if err != nil { - log.Fatalf("Greška pri kreiranju keša šablona: %v", err) + slog.Error("Greška pri kreiranju keša šablona", "error", err); os.Exit(1) } h.Templates = kes - log.Printf("Keš šablona kreiran: %d šablona", len(kes)) + slog.Info("keš šablona kreiran", "broj", len(kes)) } // Pozadinske gorutine se pokreću posle kreiranja h i rade preko h.SaBazom, @@ -309,10 +323,10 @@ func main() { r.With(doz("tema.lokalno")).Post("/profil/pozadina/stilovi", h.ProfilSacuvajPozadinuStilove) }) - log.Printf("NTech pokrenut na portu %s", port) + slog.Info("NTech pokrenut", "port", port) err = http.ListenAndServe(":"+port, r) if err != nil { - log.Fatalf("Greška: port %s je zauzet ili nije dostupan", port) + slog.Error("port je zauzet ili nije dostupan", "port", port); os.Exit(1) } } @@ -350,7 +364,7 @@ func ucitajTotpKljuc() ([]byte, error) { return nil, fmt.Errorf("upis ključa u ntech.env: %w", err) } os.Setenv("NTECH_TOTP_KEY", enkodiran) - log.Println("Generisan nov NTECH_TOTP_KEY i upisan u ntech.env") + slog.Info("generisan nov NTECH_TOTP_KEY i upisan u ntech.env") return kljuc, nil } @@ -363,7 +377,7 @@ func napraviBackup(db *sql.DB, putanjaBaze string) { folder := "backups" if err := os.MkdirAll(folder, 0755); err != nil { - log.Printf("backup: ne mogu kreirati folder: %v", err) + slog.Error("backup: ne mogu kreirati folder", "error", err) return } @@ -371,11 +385,11 @@ func napraviBackup(db *sql.DB, putanjaBaze string) { odrediste := filepath.Join(folder, ime) if _, err := db.ExecContext(context.Background(), "VACUUM INTO ?", odrediste); err != nil { - log.Printf("backup: greška pri pravljenju backup-a: %v", err) + slog.Error("backup: greška pri pravljenju backup-a", "error", err) return } - log.Printf("Backup kreiran: %s", odrediste) + slog.Info("backup kreiran", "putanja", odrediste) ocistiStareBackupe(folder, procitajIntPodesavanje(db, "backup_broj_kopija", 7)) } diff --git a/internal/config/setup.go b/internal/config/setup.go index 8ab1d6a..45ddfcd 100644 --- a/internal/config/setup.go +++ b/internal/config/setup.go @@ -5,9 +5,10 @@ import ( "encoding/json" "fmt" "io/fs" - "log" + "log/slog" "net" "net/http" + "os" "strings" "github.com/go-chi/chi/v5" @@ -48,7 +49,7 @@ func nadjiLokalneAdrese() []string { func PokreniSetup(fsys fs.FS) { port := NadjiSlobodanPort() if port == 0 { - log.Fatal("ntech: setup: nije pronađen nijedan slobodan port") + slog.Error("setup: nije pronađen nijedan slobodan port"); os.Exit(1) } gotov := make(chan struct{}) @@ -102,7 +103,7 @@ func PokreniSetup(fsys fs.FS) { go func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { - log.Fatalf("ntech: setup server: %v", err) + slog.Error("setup server", "error", err); os.Exit(1) } }() diff --git a/internal/db/sqlite/migracije.go b/internal/db/sqlite/migracije.go index b4887fd..789bcfb 100644 --- a/internal/db/sqlite/migracije.go +++ b/internal/db/sqlite/migracije.go @@ -4,7 +4,7 @@ import ( "database/sql" "fmt" "io/fs" - "log" + "log/slog" "path" "sort" "strings" @@ -87,7 +87,7 @@ func PokreniMigracije(db *sql.DB, fsys fs.FS) error { // "duplicate column name" znači da kolona već postoji — željeno stanje je ispunjeno, // pa nastavljamo i beležimo migraciju kao izvršenu if strings.Contains(err.Error(), "duplicate column name") { - log.Printf("Upozorenje: migration %s: kolona već postoji, preskačemo", naziv) + slog.Warn("migracija: kolona već postoji, preskačemo", "migracija", naziv) } else { return fmt.Errorf("ntech: PokreniMigracije: izvršavanje %s: %w", naziv, err) } diff --git a/internal/handler/dashboard.go b/internal/handler/dashboard.go index 18eb4ba..02342c3 100644 --- a/internal/handler/dashboard.go +++ b/internal/handler/dashboard.go @@ -1,7 +1,7 @@ package handler import ( - "log" + "log/slog" "net/http" "time" @@ -39,14 +39,14 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) { if err := h.DB.QueryRowContext(ctx, "SELECT COUNT(*) FROM artikli", ).Scan(&brojArtikala); err != nil { - log.Printf("dashboard: broj artikala: %v", err) + slog.Error("dashboard: broj artikala", "error", err) } if err := h.DB.QueryRowContext(ctx, ` SELECT COUNT(*) FROM servisni_nalozi WHERE status != 'Završeno'`, ).Scan(&aktivniServisi); err != nil { - log.Printf("dashboard: aktivni servisi: %v", err) + slog.Error("dashboard: aktivni servisi", "error", err) } // prihod se dohvata samo ako korisnik ima dozvolu dashboard.prihod @@ -56,14 +56,14 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) { SELECT COALESCE(SUM(ukupno), 0) FROM prodajni_nalozi WHERE substr(datum, 1, 7) = strftime('%Y-%m', 'now', 'localtime')`, ).Scan(&prihodOvogMeseca); err != nil { - log.Printf("dashboard: prihod ovog meseca: %v", err) + slog.Error("dashboard: prihod ovog meseca", "error", err) } } if err := h.DB.QueryRowContext(ctx, "SELECT COUNT(*) FROM artikli WHERE kolicina <= kolicina_min", ).Scan(&kriticnaZaliha); err != nil { - log.Printf("dashboard: kriticna zaliha: %v", err) + slog.Error("dashboard: kriticna zaliha", "error", err) } korisnikFilter := appdb.PodsetnikFilter{} @@ -71,7 +71,7 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) { korisnikFilter.KorisnikID = &korisnikDash.ID } if n, err := h.PodsetnikRepo.BrojAktivnih(ctx, korisnikFilter); err != nil { - log.Printf("dashboard: aktivni podsetnici: %v", err) + slog.Error("dashboard: aktivni podsetnici", "error", err) } else { aktivniPodsetnici = n } @@ -81,7 +81,7 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) { SELECT uredjaj, status, datum_prijema FROM servisni_nalozi ORDER BY datum_prijema DESC LIMIT 5`) if err != nil { - log.Printf("dashboard: poslednji servisi: %v", err) + slog.Error("dashboard: poslednji servisi", "error", err) } var poslednjiServisi []model.StavkaServisa @@ -104,7 +104,7 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) { WHERE kolicina <= kolicina_min ORDER BY kolicina ASC LIMIT 5`) if err != nil { - log.Printf("dashboard: kriticne zalihe: %v", err) + slog.Error("dashboard: kriticne zalihe", "error", err) } var kriticneZalihe []model.StavkaZalihe @@ -132,7 +132,7 @@ func (h *Handler) Dashboard(w http.ResponseWriter, r *http.Request) { LEFT JOIN klijent_prikaz kp ON kp.id = pn.klijent_id ORDER BY pn.datum DESC LIMIT 5`) if err != nil { - log.Printf("dashboard: poslednje prodaje: %v", err) + slog.Error("dashboard: poslednje prodaje", "error", err) } var poslednjeProdaje []model.StavkaProdajePregled diff --git a/internal/handler/izvestaji.go b/internal/handler/izvestaji.go index 2ee8900..1cbcd14 100644 --- a/internal/handler/izvestaji.go +++ b/internal/handler/izvestaji.go @@ -4,7 +4,7 @@ import ( "encoding/json" "fmt" "html/template" - "log" + "log/slog" "net/http" "time" @@ -92,7 +92,7 @@ func (h *Handler) Izvestaji(w http.ResponseWriter, r *http.Request) { WHERE substr(datum, 1, 10) >= date('now', '-11 months', 'start of month') GROUP BY substr(datum, 1, 7)`) if err != nil { - log.Printf("izvestaji: prihod prodaja: %v", err) + slog.Error("izvestaji: prihod prodaja", "error", err) } else { defer prodajaRed.Close() for prodajaRed.Next() { @@ -113,7 +113,7 @@ func (h *Handler) Izvestaji(w http.ResponseWriter, r *http.Request) { AND substr(datum_zavrsetka, 1, 10) >= date('now', '-11 months', 'start of month') GROUP BY substr(datum_zavrsetka, 1, 7)`) if err != nil { - log.Printf("izvestaji: prihod servis: %v", err) + slog.Error("izvestaji: prihod servis", "error", err) } else { defer servisRed.Close() for servisRed.Next() { @@ -171,7 +171,7 @@ func (h *Handler) Izvestaji(w http.ResponseWriter, r *http.Request) { var stariNalozi []StariNalog if err != nil { - log.Printf("izvestaji: stari nalozi: %v", err) + slog.Error("izvestaji: stari nalozi", "error", err) } else { defer stariRed.Close() for stariRed.Next() { @@ -197,7 +197,7 @@ func (h *Handler) Izvestaji(w http.ResponseWriter, r *http.Request) { var topArtikli []TopArtikal if err != nil { - log.Printf("izvestaji: top artikli: %v", err) + slog.Error("izvestaji: top artikli", "error", err) } else { defer artRed.Close() for artRed.Next() { @@ -231,7 +231,7 @@ func (h *Handler) Izvestaji(w http.ResponseWriter, r *http.Request) { var topKlijenti []TopKlijent if err != nil { - log.Printf("izvestaji: top klijenti: %v", err) + slog.Error("izvestaji: top klijenti", "error", err) } else { defer klijRed.Close() for klijRed.Next() { diff --git a/internal/handler/kes.go b/internal/handler/kes.go index d7d758e..b346ea5 100644 --- a/internal/handler/kes.go +++ b/internal/handler/kes.go @@ -4,7 +4,7 @@ import ( "fmt" "html/template" "io/fs" - "log" + "log/slog" "net/http" ) @@ -90,7 +90,7 @@ func (h *Handler) renderujTemplate(w http.ResponseWriter, ime string, podaci any if h.Templates != nil { t, ok := h.Templates[ime] if !ok { - log.Printf("kes: šablon '%s' nije pronađen", ime) + slog.Error("šablon nije pronađen", "ime", ime) http.Error(w, "Greška pri učitavanju stranice", http.StatusInternalServerError) return } @@ -101,14 +101,14 @@ func (h *Handler) renderujTemplate(w http.ResponseWriter, ime string, podaci any fajlovi = append(fajlovi, "web/templates/stranice/"+ime+".html") var err error if tmpl, err = template.New(ime).Funcs(sablonskeFunkcije).ParseFS(h.TemplatesFS, fajlovi...); err != nil { - log.Printf("greška pri parsiranju šablona %s: %v", ime, err) + slog.Error("greška pri parsiranju šablona", "ime", ime, "error", err) http.Error(w, "Greška pri učitavanju stranice", http.StatusInternalServerError) return } } if err := tmpl.ExecuteTemplate(w, "base", podaci); err != nil { - log.Printf("greška pri renderovanju šablona %s: %v", ime, err) + slog.Error("greška pri renderovanju šablona", "ime", ime, "error", err) http.Error(w, "Greška pri prikazu stranice", http.StatusInternalServerError) } } @@ -120,7 +120,7 @@ func (h *Handler) renderujStandalone(w http.ResponseWriter, ime string, podaci a if h.Templates != nil { t, ok := h.Templates[ime] if !ok { - log.Printf("kes: standalone šablon '%s' nije pronađen", ime) + slog.Error("standalone šablon nije pronađen", "ime", ime) http.Error(w, "Greška pri učitavanju stranice", http.StatusInternalServerError) return } @@ -128,14 +128,14 @@ func (h *Handler) renderujStandalone(w http.ResponseWriter, ime string, podaci a } else { var err error if tmpl, err = template.ParseFS(h.TemplatesFS, "web/templates/stranice/"+ime+".html"); err != nil { - log.Printf("greška pri parsiranju šablona %s: %v", ime, err) + slog.Error("greška pri parsiranju šablona", "ime", ime, "error", err) http.Error(w, "Greška pri učitavanju stranice", http.StatusInternalServerError) return } } if err := tmpl.Execute(w, podaci); err != nil { - log.Printf("greška pri renderovanju šablona %s: %v", ime, err) + slog.Error("greška pri renderovanju šablona", "ime", ime, "error", err) http.Error(w, "Greška pri prikazu stranice", http.StatusInternalServerError) } } diff --git a/internal/handler/klijent.go b/internal/handler/klijent.go index 875dc4e..46d71f4 100644 --- a/internal/handler/klijent.go +++ b/internal/handler/klijent.go @@ -1,7 +1,7 @@ package handler import ( - "log" + "log/slog" "net/http" "strings" @@ -101,7 +101,7 @@ func (h *Handler) SacuvajKlijenta(w http.ResponseWriter, r *http.Request) { } if _, err := h.KlijentiRepo.Kreiraj(r.Context(), &klijent); err != nil { - log.Printf("greška pri čuvanju klijenta: %v", err) + slog.Error("greška pri čuvanju klijenta", "error", err) podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB) ps := h.popuniPodaciStranice(r, podesavanja) ps.Stranica = "klijenti" @@ -182,7 +182,7 @@ func (h *Handler) SacuvajIzmenuKlijenta(w http.ResponseWriter, r *http.Request) klijent.ID = id if err := h.KlijentiRepo.Izmeni(r.Context(), &klijent); err != nil { - log.Printf("greška pri čuvanju izmene klijenta: %v", err) + slog.Error("greška pri čuvanju izmene klijenta", "error", err) podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB) ps := h.popuniPodaciStranice(r, podesavanja) ps.Stranica = "klijenti" diff --git a/internal/handler/podesavanja.go b/internal/handler/podesavanja.go index 61f37fb..c8d79bd 100644 --- a/internal/handler/podesavanja.go +++ b/internal/handler/podesavanja.go @@ -5,7 +5,7 @@ import ( "encoding/hex" "fmt" "io" - "log" + "log/slog" "net/http" "os" "path/filepath" @@ -155,14 +155,14 @@ func (h *Handler) VratiBackup(w http.ResponseWriter, r *http.Request) { // pre obnove, sačuvaj trenutno stanje baze sigurnosni := filepath.Join("backups", fmt.Sprintf("ntech_%s_pred_vracanjem.db", time.Now().Format("20060102_150405"))) if _, err := h.DB.ExecContext(r.Context(), "VACUUM INTO ?", sigurnosni); err != nil { - log.Printf("vrati backup: greška pri kreiranju sigurnosne kopije: %v", err) + slog.Error("vrati backup: greška pri kreiranju sigurnosne kopije", "error", err) http.Redirect(w, r, "/podesavanja?backup_greska=Greška+pri+kreiranju+sigurnosne+kopije", http.StatusSeeOther) return } // isprazni WAL u glavni fajl if _, err := h.DB.ExecContext(r.Context(), "PRAGMA wal_checkpoint(TRUNCATE)"); err != nil { - log.Printf("vrati backup: wal_checkpoint greška: %v", err) + slog.Error("vrati backup: wal_checkpoint greška", "error", err) } // Sama zamena baze (zatvaranje stare, kopiranje, otvaranje nove) radi se u @@ -178,10 +178,10 @@ func (h *Handler) VratiBackup(w http.ResponseWriter, r *http.Request) { defer h.mu.Unlock() if err := h.DB.Close(); err != nil { - log.Printf("vrati backup: greška pri zatvaranju baze: %v", err) + slog.Error("vrati backup: greška pri zatvaranju baze", "error", err) } if err := kopiraFajl(putanjaBackupa, h.PutanjaBaze); err != nil { - log.Printf("vrati backup: greška pri kopiranju (baza je zatvorena, potreban restart): %v", err) + slog.Error("vrati backup: greška pri kopiranju (baza je zatvorena, potreban restart)", "error", err) return } os.Remove(h.PutanjaBaze + "-wal") @@ -189,11 +189,11 @@ func (h *Handler) VratiBackup(w http.ResponseWriter, r *http.Request) { novaDB, err := ntechsqlite.OtvoriDB(h.PutanjaBaze) if err != nil { - log.Printf("vrati backup: greška pri otvaranju nove baze (potreban restart): %v", err) + slog.Error("vrati backup: greška pri otvaranju nove baze (potreban restart)", "error", err) return } h.reinicijalizujRepozitorijume(novaDB) - log.Printf("Baza uspešno obnovljena iz: %s", ime) + slog.Info("baza uspešno obnovljena", "izvor", ime) }() http.Redirect(w, r, "/podesavanja?sacuvano=vraceno", http.StatusSeeOther) @@ -364,14 +364,14 @@ func (h *Handler) OtpremiLogo(w http.ResponseWriter, r *http.Request) { odrediste := "web/static/uploads/logo" + ext dst, err := os.Create(odrediste) if err != nil { - log.Printf("upload loga: ne mogu kreirati fajl: %v", err) + slog.Error("upload loga: ne mogu kreirati fajl", "error", err) http.Redirect(w, r, "/podesavanja?logo_greska=Greška+pri+čuvanju+fajla", http.StatusSeeOther) return } defer dst.Close() if _, err := io.Copy(dst, fajl); err != nil { - log.Printf("upload loga: greška pri kopiranju: %v", err) + slog.Error("upload loga: greška pri kopiranju", "error", err) http.Redirect(w, r, "/podesavanja?logo_greska=Greška+pri+čuvanju+fajla", http.StatusSeeOther) return } @@ -379,7 +379,7 @@ func (h *Handler) OtpremiLogo(w http.ResponseWriter, r *http.Request) { // timestamp u URL-u sprečava browser da koristi staru keširanu sliku putanja := fmt.Sprintf("/static/uploads/logo%s?v=%d", ext, time.Now().Unix()) if err := ntechsqlite.SacuvajPodesavanje(r.Context(), h.DB, "logo_putanja", putanja); err != nil { - log.Printf("upload loga: greška pri čuvanju putanje: %v", err) + slog.Error("upload loga: greška pri čuvanju putanje", "error", err) http.Redirect(w, r, "/podesavanja?logo_greska=Greška+pri+čuvanju+podešavanja", http.StatusSeeOther) return } @@ -463,7 +463,7 @@ func (h *Handler) OtpremiLoginPozadinu(w http.ResponseWriter, r *http.Request) { novoIme, err := generisiImeUploada(ext) if err != nil { - log.Printf("upload login pozadine: greška pri generisanju imena: %v", err) + slog.Error("upload login pozadine: greška pri generisanju imena", "error", err) middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju fajla.") http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther) return @@ -472,7 +472,7 @@ func (h *Handler) OtpremiLoginPozadinu(w http.ResponseWriter, r *http.Request) { odrediste := filepath.Join("web/static/uploads", novoIme) dst, err := os.Create(odrediste) if err != nil { - log.Printf("upload login pozadine: ne mogu kreirati fajl: %v", err) + slog.Error("upload login pozadine: ne mogu kreirati fajl", "error", err) middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju fajla.") http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther) return @@ -480,7 +480,7 @@ func (h *Handler) OtpremiLoginPozadinu(w http.ResponseWriter, r *http.Request) { defer dst.Close() if _, err := io.Copy(dst, fajl); err != nil { - log.Printf("upload login pozadine: greška pri kopiranju: %v", err) + slog.Error("upload login pozadine: greška pri kopiranju", "error", err) middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju fajla.") http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther) return @@ -488,7 +488,7 @@ func (h *Handler) OtpremiLoginPozadinu(w http.ResponseWriter, r *http.Request) { putanja := fmt.Sprintf("/static/uploads/%s?v=%d", novoIme, time.Now().Unix()) if err := ntechsqlite.SacuvajPodesavanje(r.Context(), h.DB, "login_pozadina", putanja); err != nil { - log.Printf("upload login pozadine: greška pri čuvanju putanje: %v", err) + slog.Error("upload login pozadine: greška pri čuvanju putanje", "error", err) middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju podešavanja.") http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther) return @@ -514,7 +514,7 @@ func (h *Handler) UkloniLoginPozadinu(w http.ResponseWriter, r *http.Request) { } if err := ntechsqlite.SacuvajPodesavanje(r.Context(), h.DB, "login_pozadina", ""); err != nil { - log.Printf("ukloni login pozadinu: greška pri čuvanju: %v", err) + slog.Error("ukloni login pozadinu: greška pri čuvanju", "error", err) middleware.SetFlash(w, r, h.DB, "greska", "Greška pri uklanjanju slike.") http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther) return @@ -572,7 +572,7 @@ func (h *Handler) SacuvajLoginPozadinaStilove(w http.ResponseWriter, r *http.Req "login_pozadina_zatamnjenje_kartice": zatamnjenjeKarticeStr, } { if err := ntechsqlite.SacuvajPodesavanje(r.Context(), h.DB, kljuc, vrednost); err != nil { - log.Printf("stilovi login pozadine: greška pri čuvanju %s: %v", kljuc, err) + slog.Error("greška pri čuvanju stila login pozadine", "kljuc", kljuc, "error", err) middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju podešavanja.") http.Redirect(w, r, "/admin/podesavanja/izgled", http.StatusSeeOther) return diff --git a/internal/handler/podsetnici.go b/internal/handler/podsetnici.go index ea18812..a4b100c 100644 --- a/internal/handler/podsetnici.go +++ b/internal/handler/podsetnici.go @@ -1,7 +1,7 @@ package handler import ( - "log" + "log/slog" "net/http" "strconv" "strings" @@ -116,7 +116,7 @@ func (h *Handler) SacuvajPodsetnik(w http.ResponseWriter, r *http.Request) { } if _, err := h.PodsetnikRepo.Kreiraj(r.Context(), &podsetnik); err != nil { - log.Printf("greška pri čuvanju podsetnika: %v", err) + slog.Error("greška pri čuvanju podsetnika", "error", err) h.prikaziGreskuPodsetnika(w, r, k, podsetnik, "Došlo je do greške pri čuvanju. Pokušajte ponovo.", false) return } @@ -187,7 +187,7 @@ func (h *Handler) SacuvajIzmenePodsetnika(w http.ResponseWriter, r *http.Request } if err := h.PodsetnikRepo.Izmeni(r.Context(), &podsetnik); err != nil { - log.Printf("greška pri čuvanju izmene podsetnika: %v", err) + slog.Error("greška pri čuvanju izmene podsetnika", "error", err) h.prikaziGreskuPodsetnika(w, r, k, podsetnik, "Došlo je do greške pri čuvanju. Pokušajte ponovo.", true) return } diff --git a/internal/handler/prodaja.go b/internal/handler/prodaja.go index a96b979..b75fd78 100644 --- a/internal/handler/prodaja.go +++ b/internal/handler/prodaja.go @@ -4,7 +4,7 @@ import ( "encoding/json" "errors" "html/template" - "log" + "log/slog" "net/http" "strconv" "strings" @@ -171,7 +171,7 @@ func (h *Handler) SacuvajProdaju(w http.ResponseWriter, r *http.Request) { brojNaloga, err := h.ProdajaRepo.SledeciBroj(r.Context()) if err != nil { - log.Printf("greška pri generisanju broja naloga: %v", err) + slog.Error("greška pri generisanju broja naloga", "error", err) renderujGresku("Greška pri generisanju broja naloga.") return } @@ -191,7 +191,7 @@ func (h *Handler) SacuvajProdaju(w http.ResponseWriter, r *http.Request) { if errors.As(err, &errStanje) { renderujGresku(errStanje.Error()) } else { - log.Printf("greška pri čuvanju prodaje: %v", err) + slog.Error("greška pri čuvanju prodaje", "error", err) renderujGresku("Greška pri čuvanju prodajnog naloga.") } return @@ -403,7 +403,7 @@ func (h *Handler) StornoProdaje(w http.ResponseWriter, r *http.Request) { } razlog := strings.TrimSpace(r.FormValue("razlog")) if err := h.ProdajaRepo.Storno(r.Context(), id, razlog, &k.ID); err != nil { - log.Printf("greška pri storniranju naloga: %v", err) + slog.Error("greška pri storniranju naloga", "error", err) middleware.SetFlash(w, r, h.DB, "greska", "Greška pri storniranju. Možda je nalog već storniran.") http.Redirect(w, r, "/prodaja/"+strconv.FormatInt(id, 10), http.StatusSeeOther) return diff --git a/internal/handler/profil.go b/internal/handler/profil.go index 8e21138..c2415c1 100644 --- a/internal/handler/profil.go +++ b/internal/handler/profil.go @@ -3,7 +3,7 @@ package handler import ( "fmt" "io" - "log" + "log/slog" "net/http" "os" "path/filepath" @@ -132,7 +132,7 @@ func (h *Handler) ProfilOtpremiPozadinu(w http.ResponseWriter, r *http.Request) odrediste := filepath.Join("web/static/uploads", novoIme) dst, err := os.Create(odrediste) if err != nil { - log.Printf("ProfilOtpremiPozadinu: ne mogu kreirati fajl: %v", err) + slog.Error("ProfilOtpremiPozadinu: ne mogu kreirati fajl", "error", err) middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju fajla.") http.Redirect(w, r, "/profil/tema", http.StatusSeeOther) return @@ -140,7 +140,7 @@ func (h *Handler) ProfilOtpremiPozadinu(w http.ResponseWriter, r *http.Request) defer dst.Close() if _, err := io.Copy(dst, fajl); err != nil { - log.Printf("ProfilOtpremiPozadinu: greška pri kopiranju: %v", err) + slog.Error("ProfilOtpremiPozadinu: greška pri kopiranju", "error", err) middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju fajla.") http.Redirect(w, r, "/profil/tema", http.StatusSeeOther) return @@ -168,7 +168,7 @@ func (h *Handler) ProfilOtpremiPozadinu(w http.ResponseWriter, r *http.Request) } if err := h.KorisniciRepo.SacuvajLokalnuPozadinu(r.Context(), k.ID, putanja, opacity, blur, blurPozadine, glassOpacity); err != nil { - log.Printf("ProfilOtpremiPozadinu: greška pri čuvanju: %v", err) + slog.Error("ProfilOtpremiPozadinu: greška pri čuvanju", "error", err) middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju podešavanja.") http.Redirect(w, r, "/profil/tema", http.StatusSeeOther) return @@ -193,7 +193,7 @@ func (h *Handler) ProfilUkloniPozadinu(w http.ResponseWriter, r *http.Request) { } if err := h.KorisniciRepo.SacuvajLokalnuPozadinu(r.Context(), k.ID, "", "50", "12", "0", "10"); err != nil { - log.Printf("ProfilUkloniPozadinu: %v", err) + slog.Error("ProfilUkloniPozadinu", "error", err) middleware.SetFlash(w, r, h.DB, "greska", "Greška pri uklanjanju slike.") http.Redirect(w, r, "/profil/tema", http.StatusSeeOther) return @@ -241,7 +241,7 @@ func (h *Handler) ProfilSacuvajPozadinuStilove(w http.ResponseWriter, r *http.Re } if err := h.KorisniciRepo.SacuvajLokalnuPozadinu(r.Context(), k.ID, pozadina, opacity, blur, blurPozadineSt, glassOpacitySt); err != nil { - log.Printf("ProfilSacuvajPozadinuStilove: %v", err) + slog.Error("ProfilSacuvajPozadinuStilove", "error", err) middleware.SetFlash(w, r, h.DB, "greska", "Greška pri čuvanju podešavanja.") http.Redirect(w, r, "/profil/tema", http.StatusSeeOther) return diff --git a/internal/handler/servis.go b/internal/handler/servis.go index a8a9031..fc200e1 100644 --- a/internal/handler/servis.go +++ b/internal/handler/servis.go @@ -1,7 +1,7 @@ package handler import ( - "log" + "log/slog" "net/http" "strconv" "strings" @@ -152,7 +152,7 @@ func (h *Handler) SacuvajNalog(w http.ResponseWriter, r *http.Request) { id, err := h.ServisRepo.Kreiraj(r.Context(), &nalog) if err != nil { - log.Printf("greška pri čuvanju naloga: %v", err) + slog.Error("greška pri čuvanju naloga", "error", err) podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB) klijenti, _ := h.KlijentiRepo.Lista(r.Context(), "") tehnicari, _ := h.KorisniciRepo.Lista(r.Context()) @@ -258,7 +258,7 @@ func (h *Handler) SacuvajIzmenaNaloga(w http.ResponseWriter, r *http.Request) { nalog.ID = id if err := h.ServisRepo.Izmeni(r.Context(), &nalog); err != nil { - log.Printf("greška pri čuvanju izmene naloga: %v", err) + slog.Error("greška pri čuvanju izmene naloga", "error", err) podesavanja, _ := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB) klijenti, _ := h.KlijentiRepo.Lista(r.Context(), "") tehnicari, _ := h.KorisniciRepo.Lista(r.Context()) @@ -337,13 +337,13 @@ func (h *Handler) DetaljiNaloga(w http.ResponseWriter, r *http.Request) { delovi, err := h.ServisniDeloviRepo.DohvatiZaNalog(r.Context(), id) if err != nil { - log.Printf("greška pri učitavanju delova: %v", err) + slog.Error("greška pri učitavanju delova", "error", err) } appdb := appdbPkg.ArtikalFilter{} artikli, err := h.Artikli.Lista(r.Context(), appdb) if err != nil { - log.Printf("greška pri učitavanju artikala: %v", err) + slog.Error("greška pri učitavanju artikala", "error", err) } ps := h.popuniPodaciStranice(r, podesavanja) @@ -402,7 +402,7 @@ func (h *Handler) DodajDeloNalogu(w http.ResponseWriter, r *http.Request) { } if _, err := h.ServisniDeloviRepo.Dodaj(r.Context(), nalogID, artikalID, kolicina, cena, &k.ID); err != nil { - log.Printf("greška pri dodavanju dela: %v", err) + slog.Error("greška pri dodavanju dela", "error", err) middleware.SetFlash(w, r, h.DB, "greska", "Greška pri dodavanju dela. Proverite stanje na magacinu.") http.Redirect(w, r, "/servis/"+strconv.FormatInt(nalogID, 10), http.StatusSeeOther) return @@ -432,7 +432,7 @@ func (h *Handler) ObrisiDeloNaloga(w http.ResponseWriter, r *http.Request) { } if err := h.ServisniDeloviRepo.Obrisi(r.Context(), deoID, &k.ID); err != nil { - log.Printf("greška pri brisanju dela: %v", err) + slog.Error("greška pri brisanju dela", "error", err) middleware.SetFlash(w, r, h.DB, "greska", "Greška pri uklanjanju dela.") } else { middleware.SetFlash(w, r, h.DB, "uspeh", "Deo je uklonjen.")