chore: update logger

This commit is contained in:
Steven 2024-02-29 23:54:43 +08:00
parent 12f4d3a10d
commit dfa78cac49
14 changed files with 87 additions and 146 deletions

View File

@ -3,6 +3,7 @@ package main
import (
"context"
"fmt"
"log/slog"
"net/http"
"os"
"os/signal"
@ -10,10 +11,8 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.uber.org/zap"
"github.com/usememos/memos/internal/jobs"
"github.com/usememos/memos/internal/log"
"github.com/usememos/memos/server"
_profile "github.com/usememos/memos/server/profile"
"github.com/usememos/memos/store"
@ -49,26 +48,26 @@ var (
dbDriver, err := db.NewDBDriver(profile)
if err != nil {
cancel()
log.Error("failed to create db driver", zap.Error(err))
slog.Error("failed to create db driver", err)
return
}
if err := dbDriver.Migrate(ctx); err != nil {
cancel()
log.Error("failed to migrate db", zap.Error(err))
slog.Error("failed to migrate database", err)
return
}
storeInstance := store.New(dbDriver, profile)
if err := storeInstance.MigrateManually(ctx); err != nil {
cancel()
log.Error("failed to migrate manually", zap.Error(err))
slog.Error("failed to migrate manually", err)
return
}
s, err := server.NewServer(ctx, profile, storeInstance)
if err != nil {
cancel()
log.Error("failed to create server", zap.Error(err))
slog.Error("failed to create server", err)
return
}
@ -78,8 +77,7 @@ var (
// which is taken as the graceful shutdown signal for many systems, eg., Kubernetes, Gunicorn.
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
sig := <-c
log.Info(fmt.Sprintf("%s received.\n", sig.String()))
<-c
s.Shutdown(ctx)
cancel()
}()
@ -91,7 +89,7 @@ var (
if err := s.Start(ctx); err != nil {
if err != http.ErrServerClosed {
log.Error("failed to start server", zap.Error(err))
slog.Error("failed to start server", err)
cancel()
}
}
@ -103,7 +101,6 @@ var (
)
func Execute() error {
defer log.Sync()
return rootCmd.Execute()
}

View File

@ -3,13 +3,12 @@ package jobs
import (
"context"
"encoding/json"
"log/slog"
"strings"
"time"
"github.com/pkg/errors"
"go.uber.org/zap"
"github.com/usememos/memos/internal/log"
"github.com/usememos/memos/plugin/storage/s3"
apiv1 "github.com/usememos/memos/server/route/api/v1"
"github.com/usememos/memos/store"
@ -19,11 +18,10 @@ import (
// It uses S3 client to generate presigned URLs and updates the corresponding resources in the store.
func RunPreSignLinks(ctx context.Context, dataStore *store.Store) {
for {
started := time.Now()
if err := signExternalLinks(ctx, dataStore); err != nil {
log.Warn("failed sign external links", zap.Error(err))
slog.Error("failed to pre-sign links", err)
} else {
log.Info("links pre-signed", zap.Duration("duration", time.Since(started)))
slog.Debug("pre-signed links")
}
select {
case <-time.After(s3.LinkLifetime / 2):
@ -69,7 +67,7 @@ func signExternalLinks(ctx context.Context, dataStore *store.Store) error {
}
newLink, err := objectStore.PreSignLink(ctx, res.ExternalLink)
if err != nil {
log.Warn("failed pre-sign link", zap.Int32("resource", res.ID), zap.String("link", res.ExternalLink), zap.Error(err))
slog.Error("failed to pre-sign link", err)
continue // do not fail - we may want update left over links too
}
now := time.Now().Unix()

View File

@ -1,66 +0,0 @@
package log
import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var (
// `gl` is the global logger.
// Other packages should use public methods such as Info/Error to do the logging.
// For other types of logging, e.g. logging to a separate file, they should use their own loggers.
gl *zap.Logger
gLevel zap.AtomicLevel
)
// Initializes the global console logger.
func init() {
gLevel = zap.NewAtomicLevelAt(zap.InfoLevel)
gl, _ = zap.Config{
Level: gLevel,
Development: true,
// Use "console" to print readable stacktrace.
Encoding: "console",
EncoderConfig: zap.NewDevelopmentEncoderConfig(),
OutputPaths: []string{"stderr"},
ErrorOutputPaths: []string{"stderr"},
}.Build(
// Skip one caller stack to locate the correct caller.
zap.AddCallerSkip(1),
)
}
// SetLevel wraps the zap Level's SetLevel method.
func SetLevel(level zapcore.Level) {
gLevel.SetLevel(level)
}
// EnabledLevel wraps the zap Level's Enabled method.
func EnabledLevel(level zapcore.Level) bool {
return gLevel.Enabled(level)
}
// Debug wraps the zap Logger's Debug method.
func Debug(msg string, fields ...zap.Field) {
gl.Debug(msg, fields...)
}
// Info wraps the zap Logger's Info method.
func Info(msg string, fields ...zap.Field) {
gl.Info(msg, fields...)
}
// Warn wraps the zap Logger's Warn method.
func Warn(msg string, fields ...zap.Field) {
gl.Warn(msg, fields...)
}
// Error wraps the zap Logger's Error method.
func Error(msg string, fields ...zap.Field) {
gl.Error(msg, fields...)
}
// Sync wraps the zap Logger's Sync method.
func Sync() {
_ = gl.Sync()
}

View File

@ -1,11 +1,8 @@
package telegram
import (
"log/slog"
"path/filepath"
"go.uber.org/zap"
"github.com/usememos/memos/internal/log"
)
type Attachment struct {
@ -29,9 +26,7 @@ func (b Attachment) GetMimeType() string {
mime, ok := mimeTypes[filepath.Ext(b.FileName)]
if !ok {
// Handle unknown file extension
log.Warn("Unknown file type for ", zap.String("filename", b.FileName))
slog.Warn("Unknown file extension", slog.String("file", b.FileName))
return "application/octet-stream"
}

View File

@ -3,13 +3,9 @@ package telegram
import (
"context"
"errors"
"fmt"
"log/slog"
"strings"
"time"
"go.uber.org/zap"
"github.com/usememos/memos/internal/log"
)
type Handler interface {
@ -41,7 +37,6 @@ func (b *Bot) Start(ctx context.Context) {
continue
}
if err != nil {
log.Warn("fail to telegram.GetUpdates", zap.Error(err))
time.Sleep(errRetryWait)
continue
}
@ -56,7 +51,7 @@ func (b *Bot) Start(ctx context.Context) {
if update.CallbackQuery != nil {
err := b.handler.CallbackQueryHandle(ctx, b, *update.CallbackQuery)
if err != nil {
log.Error("fail to handle CallbackQuery", zap.Error(err))
slog.Error("fail to handle callback query", err)
}
continue
@ -70,7 +65,7 @@ func (b *Bot) Start(ctx context.Context) {
if !message.IsSupported() {
_, err := b.SendReplyMessage(ctx, message.Chat.ID, message.MessageID, "Supported messages: animation, audio, text, document, photo, video, video note, voice, other messages with caption")
if err != nil {
log.Error(fmt.Sprintf("fail to telegram.SendReplyMessage for messageID=%d", message.MessageID), zap.Error(err))
slog.Error("fail to send reply message", err)
}
continue
}
@ -88,12 +83,12 @@ func (b *Bot) Start(ctx context.Context) {
err = b.handleSingleMessages(ctx, singleMessages)
if err != nil {
log.Error("fail to handle singleMessage", zap.Error(err))
slog.Error("fail to handle plain text message", err)
}
err = b.handleGroupMessages(ctx, groupMessages)
if err != nil {
log.Error("fail to handle plain text message", zap.Error(err))
slog.Error("fail to handle media group message", err)
}
}
}

View File

@ -2,15 +2,14 @@ package v1
import (
"fmt"
"log/slog"
"net/http"
"strings"
"github.com/golang-jwt/jwt/v5"
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
"go.uber.org/zap"
"github.com/usememos/memos/internal/log"
"github.com/usememos/memos/internal/util"
storepb "github.com/usememos/memos/proto/gen/store"
"github.com/usememos/memos/server/route/api/auth"
@ -83,7 +82,7 @@ func JWTMiddleware(server *APIV1Service, next echo.HandlerFunc, secret string) e
if err != nil {
err = removeAccessTokenAndCookies(c, server.Store, userID, accessToken)
if err != nil {
log.Error("fail to remove AccessToken and Cookies", zap.Error(err))
slog.Warn("fail to remove AccessToken and Cookies", err)
}
return echo.NewHTTPError(http.StatusUnauthorized, "Invalid or expired access token")
}
@ -95,7 +94,7 @@ func JWTMiddleware(server *APIV1Service, next echo.HandlerFunc, secret string) e
if !validateAccessToken(accessToken, accessTokens) {
err = removeAccessTokenAndCookies(c, server.Store, userID, accessToken)
if err != nil {
log.Error("fail to remove AccessToken and Cookies", zap.Error(err))
slog.Warn("fail to remove AccessToken and Cookies", err)
}
return echo.NewHTTPError(http.StatusUnauthorized, "Invalid access token.")
}

View File

@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"log/slog"
"net/http"
"strconv"
"time"
@ -11,9 +12,7 @@ import (
"github.com/labstack/echo/v4"
"github.com/lithammer/shortuuid/v4"
"github.com/pkg/errors"
"go.uber.org/zap"
"github.com/usememos/memos/internal/log"
"github.com/usememos/memos/internal/util"
"github.com/usememos/memos/plugin/webhook"
storepb "github.com/usememos/memos/proto/gen/store"
@ -390,7 +389,6 @@ func (s *APIV1Service) CreateMemo(c echo.Context) error {
for _, userSetting := range userSettings {
tgUserID, err := strconv.ParseInt(userSetting.GetTelegramUserId(), 10, 64)
if err != nil {
log.Error("failed to parse Telegram UserID", zap.Error(err))
continue
}
@ -398,14 +396,13 @@ func (s *APIV1Service) CreateMemo(c echo.Context) error {
content := memoResponse.CreatorName + " Says:\n\n" + memoResponse.Content
_, err = s.telegramBot.SendMessage(ctx, tgUserID, content)
if err != nil {
log.Error("Failed to send Telegram notification", zap.Error(err))
continue
}
}
}
// Try to dispatch webhook when memo is created.
if err := s.DispatchMemoCreatedWebhook(ctx, memoResponse); err != nil {
log.Warn("Failed to dispatch memo created webhook", zap.Error(err))
slog.Warn("Failed to dispatch memo created webhook", err)
}
return c.JSON(http.StatusOK, memoResponse)
@ -627,7 +624,7 @@ func (s *APIV1Service) DeleteMemo(c echo.Context) error {
if memoMessage, err := s.convertMemoFromStore(ctx, memo); err == nil {
// Try to dispatch webhook when memo is deleted.
if err := s.DispatchMemoDeletedWebhook(ctx, memoMessage); err != nil {
log.Warn("Failed to dispatch memo deleted webhook", zap.Error(err))
slog.Warn("Failed to dispatch memo deleted webhook", err)
}
}
@ -821,7 +818,7 @@ func (s *APIV1Service) UpdateMemo(c echo.Context) error {
}
// Try to dispatch webhook when memo is updated.
if err := s.DispatchMemoUpdatedWebhook(ctx, memoResponse); err != nil {
log.Warn("Failed to dispatch memo updated webhook", zap.Error(err))
slog.Error("Failed to dispatch memo updated webhook", err)
}
return c.JSON(http.StatusOK, memoResponse)

View File

@ -17,9 +17,7 @@ import (
"github.com/labstack/echo/v4"
"github.com/lithammer/shortuuid/v4"
"github.com/pkg/errors"
"go.uber.org/zap"
"github.com/usememos/memos/internal/log"
"github.com/usememos/memos/internal/util"
"github.com/usememos/memos/plugin/storage/s3"
"github.com/usememos/memos/store"
@ -192,7 +190,6 @@ func (s *APIV1Service) UploadResource(c echo.Context) error {
if settingMaxUploadSizeMiB, err := strconv.Atoi(maxUploadSetting.Value); err == nil {
settingMaxUploadSizeBytes = settingMaxUploadSizeMiB * MebiByte
} else {
log.Warn("Failed to parse max upload size", zap.Error(err))
settingMaxUploadSizeBytes = 0
}
} else {

View File

@ -0,0 +1,44 @@
package v2
import (
"context"
"log/slog"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
type LoggerInterceptor struct {
}
func NewLoggerInterceptor() *LoggerInterceptor {
return &LoggerInterceptor{}
}
func (in *LoggerInterceptor) LoggerInterceptor(ctx context.Context, request any, serverInfo *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
resp, err := handler(ctx, request)
in.loggerInterceptorDo(ctx, serverInfo.FullMethod, err)
return resp, err
}
func (*LoggerInterceptor) loggerInterceptorDo(ctx context.Context, fullMethod string, err error) {
st := status.Convert(err)
var logLevel slog.Level
var logMsg string
switch st.Code() {
case codes.OK:
logLevel = slog.LevelInfo
logMsg = "OK"
case codes.Unauthenticated, codes.OutOfRange, codes.PermissionDenied, codes.NotFound:
logLevel = slog.LevelInfo
logMsg = "client error"
case codes.Internal, codes.Unknown, codes.DataLoss, codes.Unavailable, codes.DeadlineExceeded:
logLevel = slog.LevelError
logMsg = "server error"
default:
logLevel = slog.LevelError
logMsg = "unknown error"
}
slog.LogAttrs(ctx, logLevel, logMsg, slog.String("method", fullMethod))
}

View File

@ -6,18 +6,17 @@ import (
"context"
"encoding/json"
"fmt"
"log/slog"
"time"
"github.com/google/cel-go/cel"
"github.com/lithammer/shortuuid/v4"
"github.com/pkg/errors"
"go.uber.org/zap"
expr "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/usememos/memos/internal/log"
"github.com/usememos/memos/internal/util"
"github.com/usememos/memos/plugin/webhook"
apiv2pb "github.com/usememos/memos/proto/gen/api/v2"
@ -70,7 +69,7 @@ func (s *APIV2Service) CreateMemo(ctx context.Context, request *apiv2pb.CreateMe
}
// Try to dispatch webhook when memo is created.
if err := s.DispatchMemoCreatedWebhook(ctx, memoMessage); err != nil {
log.Warn("Failed to dispatch memo created webhook", zap.Error(err))
slog.Warn("Failed to dispatch memo created webhook", err)
}
response := &apiv2pb.CreateMemoResponse{
@ -280,7 +279,7 @@ func (s *APIV2Service) UpdateMemo(ctx context.Context, request *apiv2pb.UpdateMe
}
// Try to dispatch webhook when memo is updated.
if err := s.DispatchMemoUpdatedWebhook(ctx, memoMessage); err != nil {
log.Warn("Failed to dispatch memo updated webhook", zap.Error(err))
slog.Warn("Failed to dispatch memo updated webhook", err)
}
return &apiv2pb.UpdateMemoResponse{
@ -307,7 +306,7 @@ func (s *APIV2Service) DeleteMemo(ctx context.Context, request *apiv2pb.DeleteMe
if memoMessage, err := s.convertMemoFromStore(ctx, memo); err == nil {
// Try to dispatch webhook when memo is deleted.
if err := s.DispatchMemoDeletedWebhook(ctx, memoMessage); err != nil {
log.Warn("Failed to dispatch memo deleted webhook", zap.Error(err))
slog.Warn("Failed to dispatch memo deleted webhook", err)
}
}

View File

@ -3,18 +3,17 @@ package v2
import (
"context"
"fmt"
"log/slog"
"net"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"github.com/improbable-eng/grpc-web/go/grpcweb"
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/reflection"
"github.com/usememos/memos/internal/log"
apiv2pb "github.com/usememos/memos/proto/gen/api/v2"
"github.com/usememos/memos/server/profile"
"github.com/usememos/memos/store"
@ -45,6 +44,7 @@ func NewAPIV2Service(secret string, profile *profile.Profile, store *store.Store
authProvider := NewGRPCAuthInterceptor(store, secret)
grpcServer := grpc.NewServer(
grpc.ChainUnaryInterceptor(
NewLoggerInterceptor().LoggerInterceptor,
authProvider.AuthenticationInterceptor,
),
)
@ -138,7 +138,7 @@ func (s *APIV2Service) RegisterGateway(ctx context.Context, e *echo.Echo) error
}
go func() {
if err := s.grpcServer.Serve(listen); err != nil {
log.Error("grpc server listen error", zap.Error(err))
slog.Error("failed to start gRPC server", err)
}
}()

View File

@ -4,6 +4,7 @@ import (
"bytes"
"fmt"
"io"
"log/slog"
"net/http"
"os"
"path/filepath"
@ -14,9 +15,7 @@ import (
"github.com/disintegration/imaging"
"github.com/labstack/echo/v4"
"github.com/pkg/errors"
"go.uber.org/zap"
"github.com/usememos/memos/internal/log"
"github.com/usememos/memos/internal/util"
"github.com/usememos/memos/server/profile"
"github.com/usememos/memos/store"
@ -99,7 +98,7 @@ func (s *ResourceService) streamResource(c echo.Context) error {
thumbnailPath := filepath.Join(s.Profile.Data, thumbnailImagePath, fmt.Sprintf("%d%s", resource.ID, ext))
thumbnailBlob, err := getOrGenerateThumbnailImage(blob, thumbnailPath)
if err != nil {
log.Warn(fmt.Sprintf("failed to get or generate local thumbnail with path %s", thumbnailPath), zap.Error(err))
slog.Warn("failed to get or generate thumbnail image", err)
} else {
blob = thumbnailBlob
}

View File

@ -9,7 +9,6 @@ import (
"github.com/google/uuid"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"github.com/pkg/errors"
"github.com/usememos/memos/plugin/telegram"
@ -49,31 +48,15 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
telegramBot: telegram.NewBotWithHandler(integration.NewTelegramHandler(store)),
}
e.Use(middleware.LoggerWithConfig(middleware.LoggerConfig{
Format: `{"time":"${time_rfc3339}","latency":"${latency_human}",` +
`"method":"${method}","uri":"${uri}",` +
`"status":${status},"error":"${error}"}` + "\n",
}))
// Register CORS middleware.
e.Use(CORSMiddleware())
e.Use(middleware.TimeoutWithConfig(middleware.TimeoutConfig{
Skipper: grpcRequestSkipper,
Timeout: 30 * time.Second,
}))
serverID, err := s.getSystemServerID(ctx)
if err != nil {
return nil, errors.Wrap(err, "failed to retrieve system server ID")
}
s.ID = serverID
// Only serve frontend when it's enabled.
if profile.Frontend {
frontendService := frontend.NewFrontendService(profile, store)
frontendService.Serve(ctx, e)
}
secret := "usememos"
if profile.Mode == "prod" {
secret, err = s.getSystemSecretSessionName(ctx)
@ -88,6 +71,12 @@ func NewServer(ctx context.Context, profile *profile.Profile, store *store.Store
return c.String(http.StatusOK, "Service ready.")
})
// Only serve frontend when it's enabled.
if profile.Frontend {
frontendService := frontend.NewFrontendService(profile, store)
frontendService.Serve(ctx, e)
}
// Register API v1 endpoints.
rootGroup := e.Group("")
apiV1Service := apiv1.NewAPIV1Service(s.Secret, profile, store, s.telegramBot)

View File

@ -3,12 +3,11 @@ package mysql
import (
"context"
"database/sql"
"fmt"
"log/slog"
"github.com/go-sql-driver/mysql"
"github.com/pkg/errors"
"github.com/usememos/memos/internal/log"
"github.com/usememos/memos/server/profile"
"github.com/usememos/memos/store"
)
@ -31,7 +30,6 @@ func NewDB(profile *profile.Profile) (store.Driver, error) {
driver := DB{profile: profile}
driver.config, err = mysql.ParseDSN(dsn)
if err != nil {
log.Error(fmt.Sprintf("DSN parse error: %s", dsn))
return nil, errors.New("Parse DSN eroor")
}
@ -87,7 +85,7 @@ func (d *DB) GetCurrentDBSize(ctx context.Context) (int64, error) {
" GROUP BY `table_schema`"
rows, err := d.db.QueryContext(ctx, query, d.config.DBName)
if err != nil {
log.Error("Query db size error, make sure you have enough privilege")
slog.Error("Query db size error, make sure you have enough privilege", err)
return 0, err
}
defer rows.Close()