mirror of
https://github.com/0x2E/fusion.git
synced 2025-06-08 05:27:15 +09:00
refactor: replace zap log with slog (#150)
* refactor: replace zap log with slog * fix
This commit is contained in:
parent
5c98073f9f
commit
bc8109fe39
10 changed files with 55 additions and 79 deletions
12
api/api.go
12
api/api.go
|
@ -3,6 +3,7 @@ package api
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -10,7 +11,6 @@ import (
|
|||
"github.com/0x2e/fusion/auth"
|
||||
"github.com/0x2e/fusion/conf"
|
||||
"github.com/0x2e/fusion/frontend"
|
||||
"github.com/0x2e/fusion/pkg/logx"
|
||||
"github.com/0x2e/fusion/repo"
|
||||
"github.com/0x2e/fusion/server"
|
||||
|
||||
|
@ -35,7 +35,6 @@ type Params struct {
|
|||
|
||||
func Run(params Params) {
|
||||
r := echo.New()
|
||||
apiLogger := logx.Logger.With("module", "api")
|
||||
|
||||
if conf.Debug {
|
||||
r.Debug = true
|
||||
|
@ -43,7 +42,7 @@ func Run(params Params) {
|
|||
if len(resBody) > 500 {
|
||||
resBody = append(resBody[:500], []byte("...")...)
|
||||
}
|
||||
apiLogger.Debugw("body dump", "req", reqBody, "resp", resBody)
|
||||
slog.Debug("body dump", "req", reqBody, "resp", resBody)
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -61,9 +60,9 @@ func Run(params Params) {
|
|||
return nil
|
||||
}
|
||||
if v.Error == nil {
|
||||
apiLogger.Infow("REQUEST", "uri", v.URI, "status", v.Status)
|
||||
slog.Info("REQUEST", "uri", v.URI, "status", v.Status)
|
||||
} else {
|
||||
apiLogger.Errorw(v.Error.Error(), "uri", v.URI, "status", v.Status)
|
||||
slog.Error(v.Error.Error(), "uri", v.URI, "status", v.Status)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
@ -144,7 +143,8 @@ func Run(params Params) {
|
|||
err = r.Start(addr)
|
||||
}
|
||||
if err != nil {
|
||||
apiLogger.Fatalln(err)
|
||||
slog.Error(err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,29 +1,42 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
_ "net/http/pprof"
|
||||
"os"
|
||||
|
||||
"log/slog"
|
||||
|
||||
"github.com/0x2e/fusion/api"
|
||||
"github.com/0x2e/fusion/conf"
|
||||
"github.com/0x2e/fusion/pkg/logx"
|
||||
"github.com/0x2e/fusion/repo"
|
||||
"github.com/0x2e/fusion/service/pull"
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer logx.Logger.Sync()
|
||||
l := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
|
||||
Level: slog.LevelInfo,
|
||||
}))
|
||||
slog.SetDefault(l)
|
||||
|
||||
if conf.Debug {
|
||||
l := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
|
||||
Level: slog.LevelDebug,
|
||||
}))
|
||||
slog.SetDefault(l)
|
||||
|
||||
go func() {
|
||||
logx.Logger.Infoln(http.ListenAndServe("localhost:6060", nil))
|
||||
if err := http.ListenAndServe("localhost:6060", nil); err != nil {
|
||||
slog.Error("pprof server", "error", err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
config, err := conf.Load()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to load configuration: %v", err)
|
||||
slog.Error("failed to load configuration", "error", err)
|
||||
return
|
||||
}
|
||||
repo.Init(config.DB)
|
||||
|
||||
|
|
12
conf/conf.go
12
conf/conf.go
|
@ -3,7 +3,7 @@ package conf
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/0x2e/fusion/auth"
|
||||
|
@ -32,9 +32,9 @@ func Load() (Conf, error) {
|
|||
if !os.IsNotExist(err) {
|
||||
return Conf{}, err
|
||||
}
|
||||
log.Printf("no configuration file found at %s", dotEnvFilename)
|
||||
slog.Warn(fmt.Sprintf("no configuration file found at %s", dotEnvFilename))
|
||||
} else {
|
||||
log.Printf("read configuration from %s", dotEnvFilename)
|
||||
slog.Info(fmt.Sprintf("load configuration from %s", dotEnvFilename))
|
||||
}
|
||||
var conf struct {
|
||||
Host string `env:"HOST" envDefault:"0.0.0.0"`
|
||||
|
@ -46,11 +46,9 @@ func Load() (Conf, error) {
|
|||
TLSKey string `env:"TLS_KEY"`
|
||||
}
|
||||
if err := env.Parse(&conf); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if Debug {
|
||||
fmt.Println(conf)
|
||||
return Conf{}, err
|
||||
}
|
||||
slog.Debug("configuration loaded", "conf", conf)
|
||||
|
||||
var pwHash *auth.HashedPassword
|
||||
if conf.Password != "" {
|
||||
|
|
2
go.mod
2
go.mod
|
@ -15,7 +15,6 @@ require (
|
|||
github.com/labstack/echo/v4 v4.13.3
|
||||
github.com/mmcdole/gofeed v1.3.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/crypto v0.37.0
|
||||
gorm.io/gorm v1.25.12
|
||||
gorm.io/plugin/soft_delete v1.2.1
|
||||
|
@ -47,7 +46,6 @@ require (
|
|||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
|
|
6
go.sum
6
go.sum
|
@ -99,12 +99,6 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC
|
|||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
package logx
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/0x2e/fusion/conf"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
|
||||
var Logger = initLogger()
|
||||
|
||||
func initLogger() *zap.SugaredLogger {
|
||||
var logger *zap.Logger
|
||||
if conf.Debug {
|
||||
devConf := zap.NewDevelopmentConfig()
|
||||
devConf.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
|
||||
logger = zap.Must(devConf.Build())
|
||||
} else {
|
||||
prodConf := zap.NewProductionConfig()
|
||||
prodConf.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
|
||||
logger = zap.Must(prodConf.Build())
|
||||
|
||||
}
|
||||
return logger.Sugar()
|
||||
}
|
||||
|
||||
type Logx struct{}
|
||||
|
||||
func ContextWithLogger(ctx context.Context, l *zap.SugaredLogger) context.Context {
|
||||
return context.WithValue(ctx, Logx{}, l)
|
||||
}
|
||||
|
||||
func LoggerFromContext(ctx context.Context) *zap.SugaredLogger {
|
||||
if l, ok := ctx.Value(Logx{}).(*zap.SugaredLogger); ok {
|
||||
return l
|
||||
}
|
||||
return Logger
|
||||
}
|
|
@ -4,3 +4,13 @@ package ptr
|
|||
func To[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
|
||||
// From returns the value pointed to by the given pointer.
|
||||
// If the pointer is nil, it returns the zero value of the type.
|
||||
func From[T any](v *T) T {
|
||||
if v == nil {
|
||||
var zero T
|
||||
return zero
|
||||
}
|
||||
return *v
|
||||
}
|
||||
|
|
|
@ -2,26 +2,29 @@ package pull
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/0x2e/fusion/model"
|
||||
"github.com/0x2e/fusion/pkg/ptr"
|
||||
"github.com/0x2e/fusion/service/pull/client"
|
||||
)
|
||||
|
||||
func (p *Puller) do(ctx context.Context, f *model.Feed, force bool) error {
|
||||
logger := pullLogger.With("feed_id", f.ID, "feed_name", f.Name)
|
||||
logger := slog.With("feed_id", f.ID, "feed_link", ptr.From(f.Link))
|
||||
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
updateAction, skipReason := DecideFeedUpdateAction(f, time.Now())
|
||||
if skipReason == &SkipReasonSuspended {
|
||||
logger.Infof("skip: %s", skipReason)
|
||||
logger.Info(fmt.Sprintf("skip: %s", skipReason))
|
||||
return nil
|
||||
}
|
||||
if !force {
|
||||
switch updateAction {
|
||||
case ActionSkipUpdate:
|
||||
logger.Infof("skip: %s", skipReason)
|
||||
logger.Info(fmt.Sprintf("skip: %s", skipReason))
|
||||
return nil
|
||||
case ActionFetchUpdate:
|
||||
// Proceed to perform the fetch.
|
||||
|
@ -69,8 +72,7 @@ func DecideFeedUpdateAction(f *model.Feed, now time.Time) (FeedUpdateAction, *Fe
|
|||
backoffTime := CalculateBackoffTime(f.ConsecutiveFailures)
|
||||
timeSinceUpdate := now.Sub(f.UpdatedAt)
|
||||
if timeSinceUpdate < backoffTime {
|
||||
logger := pullLogger.With("feed_id", f.ID, "feed_name", f.Name)
|
||||
logger.Infof("%d consecutive feed update failures, so next attempt is after %v", f.ConsecutiveFailures, f.UpdatedAt.Add(backoffTime).Format(time.RFC3339))
|
||||
slog.Info(fmt.Sprintf("%d consecutive feed update failures, so next attempt is after %v", f.ConsecutiveFailures, f.UpdatedAt.Add(backoffTime).Format(time.RFC3339)), "feed_id", f.ID, "feed_link", ptr.From(f.Link))
|
||||
return ActionSkipUpdate, &SkipReasonCoolingOff
|
||||
}
|
||||
} else if now.Sub(f.UpdatedAt) < interval {
|
||||
|
|
|
@ -3,17 +3,17 @@ package pull
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/0x2e/fusion/model"
|
||||
"github.com/0x2e/fusion/pkg/logx"
|
||||
"github.com/0x2e/fusion/pkg/ptr"
|
||||
"github.com/0x2e/fusion/repo"
|
||||
)
|
||||
|
||||
var (
|
||||
interval = 30 * time.Minute
|
||||
pullLogger = logx.Logger.With("module", "puller")
|
||||
interval = 30 * time.Minute
|
||||
)
|
||||
|
||||
type FeedRepo interface {
|
||||
|
@ -52,7 +52,6 @@ func (p *Puller) Run() {
|
|||
}
|
||||
|
||||
func (p *Puller) PullAll(ctx context.Context, force bool) error {
|
||||
logger := logx.LoggerFromContext(ctx)
|
||||
ctx, cancel := context.WithTimeout(ctx, interval/2)
|
||||
defer cancel()
|
||||
|
||||
|
@ -80,8 +79,7 @@ func (p *Puller) PullAll(ctx context.Context, force bool) error {
|
|||
}()
|
||||
|
||||
if err := p.do(ctx, f, force); err != nil {
|
||||
logger := logger.With("feed_id", f.ID)
|
||||
logger.Errorln(err)
|
||||
slog.Error("failed to pull feed", "error", err, "feed_id", f.ID, "feed_link", ptr.From(f.Link))
|
||||
}
|
||||
}(f)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package pull
|
|||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"time"
|
||||
|
||||
"github.com/0x2e/fusion/model"
|
||||
|
@ -76,14 +78,14 @@ func (r *defaultSingleFeedRepo) RecordFailure(readErr error) error {
|
|||
}
|
||||
|
||||
func (p SingleFeedPuller) Pull(ctx context.Context, feed *model.Feed) error {
|
||||
logger := pullLogger.With("feed_id", feed.ID, "feed_name", feed.Name)
|
||||
logger := slog.With("feed_id", feed.ID, "feed_link", ptr.From(feed.Link))
|
||||
|
||||
// We don't exit on error, as we want to record any error in the data store.
|
||||
fetchResult, readErr := p.readFeed(ctx, *feed.Link, feed.FeedRequestOptions)
|
||||
if readErr == nil {
|
||||
logger.Infof("fetched %d items", len(fetchResult.Items))
|
||||
logger.Info(fmt.Sprintf("fetched %d items", len(fetchResult.Items)))
|
||||
} else {
|
||||
logger.Infof("fetch failed: %v", readErr)
|
||||
logger.Warn("failed to fetch feed", "error", readErr)
|
||||
}
|
||||
|
||||
return p.updateFeedInStore(feed.ID, fetchResult.Items, fetchResult.LastBuild, readErr)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue