better loggings for shortlinks

This commit is contained in:
Sergey Chubaryan 2024-09-03 17:42:38 +03:00
parent ceac105645
commit d8541f7386
7 changed files with 62 additions and 10 deletions

View File

@ -70,4 +70,15 @@ class BackendApi():
def health_get(self): def health_get(self):
response = self.http.client.get("/health") response = self.http.client.get("/health")
if response.status_code != 200: if response.status_code != 200:
raise AssertionError('something wrong') raise AssertionError('something wrong')
def shortlink_create(self, url: string) -> string:
response = self.http.client.post("/s/new?url=" + url)
if response.status_code != 200:
raise AssertionError('can not login user')
link = response.json()['link']
if link == '':
raise AssertionError('empty user token')
return link

View File

@ -0,0 +1,13 @@
from locust import FastHttpUser, task
from api import BackendApi
class ShortlinkCreate(FastHttpUser):
api: BackendApi
@task
def user_create_test(self):
self.api.shortlink_create("https://ya.ru")
def on_start(self):
self.api = BackendApi(self)

View File

@ -114,7 +114,7 @@ func (a *App) Run(p RunParams) {
} }
tracerProvider := traceSdk.NewTracerProvider( tracerProvider := traceSdk.NewTracerProvider(
traceSdk.WithSampler(traceSdk.AlwaysSample()), traceSdk.WithSampler(traceSdk.TraceIDRatioBased(0.1)),
traceSdk.WithBatcher( traceSdk.WithBatcher(
tracerExporter, tracerExporter,
traceSdk.WithMaxQueueSize(8192), traceSdk.WithMaxQueueSize(8192),

View File

@ -10,6 +10,11 @@ import (
"time" "time"
) )
var (
ErrShortlinkNotexist = fmt.Errorf("shortlink does not exist or expired")
ErrShortlinkExpired = fmt.Errorf("shortlink expired")
)
type ShortlinkService interface { type ShortlinkService interface {
CreateShortlink(ctx context.Context, url string) (string, error) CreateShortlink(ctx context.Context, url string) (string, error)
GetShortlink(ctx context.Context, id string) (string, error) GetShortlink(ctx context.Context, id string) (string, error)
@ -66,7 +71,10 @@ func (s *shortlinkService) GetShortlink(ctx context.Context, id string) (string,
return "", err return "", err
} }
if link == nil { if link == nil {
return "", fmt.Errorf("link does not exist or expired") return "", ErrShortlinkNotexist
}
if time.Now().After(link.Expiration) {
return "", ErrShortlinkExpired
} }
return link.Url, nil return link.Url, nil

View File

@ -2,6 +2,7 @@ package handlers
import ( import (
"backend/src/core/services" "backend/src/core/services"
"backend/src/logger"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/url" "net/url"
@ -13,23 +14,28 @@ type shortlinkCreateOutput struct {
Link string `json:"link"` Link string `json:"link"`
} }
func NewShortlinkCreateHandler(shortlinkService services.ShortlinkService) gin.HandlerFunc { func NewShortlinkCreateHandler(logger logger.Logger, shortlinkService services.ShortlinkService) gin.HandlerFunc {
return func(ctx *gin.Context) { return func(ctx *gin.Context) {
ctxLogger := logger.WithContext(ctx)
rawUrl := ctx.Query("url") rawUrl := ctx.Query("url")
if rawUrl == "" { if rawUrl == "" {
ctx.AbortWithError(400, fmt.Errorf("no url param")) ctxLogger.Error().Msg("url query param missing")
ctx.AbortWithError(400, fmt.Errorf("url query param missing"))
return return
} }
u, err := url.Parse(rawUrl) u, err := url.Parse(rawUrl)
if err != nil { if err != nil {
ctx.Data(500, "plain/text", []byte(err.Error())) ctxLogger.Error().Err(err).Msg("error parsing url param")
ctx.Data(400, "plain/text", []byte(err.Error()))
return return
} }
u.Scheme = "https" u.Scheme = "https"
linkId, err := shortlinkService.CreateShortlink(ctx, u.String()) linkId, err := shortlinkService.CreateShortlink(ctx, u.String())
if err != nil { if err != nil {
ctxLogger.Error().Err(err).Msg("err creating shortlink")
ctx.Data(500, "plain/text", []byte(err.Error())) ctx.Data(500, "plain/text", []byte(err.Error()))
return return
} }
@ -38,6 +44,7 @@ func NewShortlinkCreateHandler(shortlinkService services.ShortlinkService) gin.H
Link: "https://nucrea.ru/s/" + linkId, Link: "https://nucrea.ru/s/" + linkId,
}) })
if err != nil { if err != nil {
ctxLogger.Error().Err(err).Msg("err marshalling shortlink")
ctx.AbortWithError(500, err) ctx.AbortWithError(500, err)
return return
} }
@ -46,12 +53,25 @@ func NewShortlinkCreateHandler(shortlinkService services.ShortlinkService) gin.H
} }
} }
func NewShortlinkResolveHandler(shortlinkService services.ShortlinkService) gin.HandlerFunc { func NewShortlinkResolveHandler(logger logger.Logger, shortlinkService services.ShortlinkService) gin.HandlerFunc {
return func(ctx *gin.Context) { return func(ctx *gin.Context) {
ctxLogger := logger.WithContext(ctx)
linkId := ctx.Param("linkId") linkId := ctx.Param("linkId")
linkUrl, err := shortlinkService.GetShortlink(ctx, linkId) linkUrl, err := shortlinkService.GetShortlink(ctx, linkId)
if err == services.ErrShortlinkNotexist {
ctxLogger.Error().Err(err).Msg("err getting shortlink")
ctx.AbortWithError(404, err)
return
}
if err == services.ErrShortlinkExpired {
ctxLogger.Error().Err(err).Msg("err getting shortlink")
ctx.AbortWithError(404, err)
return
}
if err != nil { if err != nil {
ctxLogger.Error().Err(err).Msg("unexpected err getting shortlink")
ctx.AbortWithError(500, err) ctx.AbortWithError(500, err)
return return
} }

View File

@ -50,7 +50,7 @@ func NewUserCreateHandler(logger logger.Logger, userService services.UserService
return return
} }
if err != nil { if err != nil {
ctxLogger.Error().Err(err).Msg("create user error") ctxLogger.Error().Err(err).Msg("unexpected create user error")
c.Data(500, "plain/text", []byte(err.Error())) c.Data(500, "plain/text", []byte(err.Error()))
return return
} }

View File

@ -50,8 +50,8 @@ func New(opts NewServerOpts) *Server {
r.GET("/pooling", handlers.NewLongPoolingHandler(opts.Logger, opts.Notifier)) r.GET("/pooling", handlers.NewLongPoolingHandler(opts.Logger, opts.Notifier))
linkGroup := r.Group("/s") linkGroup := r.Group("/s")
linkGroup.POST("/new", handlers.NewShortlinkCreateHandler(opts.ShortlinkService)) linkGroup.POST("/new", handlers.NewShortlinkCreateHandler(opts.Logger, opts.ShortlinkService))
linkGroup.GET("/:linkId", handlers.NewShortlinkResolveHandler(opts.ShortlinkService)) linkGroup.GET("/:linkId", handlers.NewShortlinkResolveHandler(opts.Logger, opts.ShortlinkService))
userGroup := r.Group("/user") userGroup := r.Group("/user")
userGroup.POST("/create", handlers.NewUserCreateHandler(opts.Logger, opts.UserService)) userGroup.POST("/create", handlers.NewUserCreateHandler(opts.Logger, opts.UserService))