[feature] Add a request ID and include it in logs (#1476)

This adds a lightweight form of tracing to GTS. Each incoming request is
assigned a Request ID which we then pass on and log in all our log
lines. Any function that gets called downstream from an HTTP handler
should now emit a requestID=value pair whenever it logs something.

Co-authored-by: kim <grufwub@gmail.com>
This commit is contained in:
Daenney 2023-02-17 12:02:29 +01:00 committed by GitHub
parent b5993095fa
commit 68e6d08c76
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
118 changed files with 813 additions and 591 deletions

View file

@ -14,7 +14,6 @@ run:
linters: linters:
# enable some extra linters, see here for the list: https://golangci-lint.run/usage/linters/ # enable some extra linters, see here for the list: https://golangci-lint.run/usage/linters/
enable: enable:
- contextcheck
- forcetypeassert - forcetypeassert
- goconst - goconst
- gocritic - gocritic
@ -27,3 +26,8 @@ linters-settings:
govet: govet:
disable: disable:
- composites - composites
staticcheck:
# Enable all checks
# Disable:
# - SA1012: nil context passing
checks: ["all", "-SA1012"]

View file

@ -42,9 +42,9 @@
} }
if dry /* dick heyyoooooo */ { if dry /* dick heyyoooooo */ {
log.Infof("DRY RUN: %d items are orphaned and eligible to be pruned", pruned) log.Infof(ctx, "DRY RUN: %d items are orphaned and eligible to be pruned", pruned)
} else { } else {
log.Infof("%d orphaned items were pruned", pruned) log.Infof(ctx, "%d orphaned items were pruned", pruned)
} }
return prune.shutdown(ctx) return prune.shutdown(ctx)

View file

@ -49,9 +49,9 @@
total := pruned + uncached total := pruned + uncached
if dry /* dick heyyoooooo */ { if dry /* dick heyyoooooo */ {
log.Infof("DRY RUN: %d remote items are unused/stale and eligible to be pruned", total) log.Infof(ctx, "DRY RUN: %d remote items are unused/stale and eligible to be pruned", total)
} else { } else {
log.Infof("%d unused/stale remote items were pruned", pruned) log.Infof(ctx, "%d unused/stale remote items were pruned", pruned)
} }
return prune.shutdown(ctx) return prune.shutdown(ctx)

View file

@ -62,7 +62,7 @@
// Start creates and starts a gotosocial server // Start creates and starts a gotosocial server
var Start action.GTSAction = func(ctx context.Context) error { var Start action.GTSAction = func(ctx context.Context) error {
_, err := maxprocs.Set(maxprocs.Logger(log.Debugf)) _, err := maxprocs.Set(nil)
if err != nil { if err != nil {
return fmt.Errorf("failed to set CPU limits from cgroup: %s", err) return fmt.Errorf("failed to set CPU limits from cgroup: %s", err)
} }
@ -156,6 +156,9 @@
// attach global middlewares which are used for every request // attach global middlewares which are used for every request
router.AttachGlobalMiddleware( router.AttachGlobalMiddleware(
middleware.AddRequestID(config.GetRequestIDHeader()),
// note: hooks adding ctx fields must be ABOVE
// the logger, otherwise won't be accessible.
middleware.Logger(), middleware.Logger(),
middleware.UserAgent(), middleware.UserAgent(),
middleware.CORS(), middleware.CORS(),
@ -237,13 +240,13 @@
sigs := make(chan os.Signal, 1) sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
sig := <-sigs // block until signal received sig := <-sigs // block until signal received
log.Infof("received signal %s, shutting down", sig) log.Infof(ctx, "received signal %s, shutting down", sig)
// close down all running services in order // close down all running services in order
if err := gts.Stop(ctx); err != nil { if err := gts.Stop(ctx); err != nil {
return fmt.Errorf("error closing gotosocial service: %s", err) return fmt.Errorf("error closing gotosocial service: %s", err)
} }
log.Info("done! exiting...") log.Info(ctx, "done! exiting...")
return nil return nil
} }

View file

@ -155,7 +155,7 @@
sigs := make(chan os.Signal, 1) sigs := make(chan os.Signal, 1)
signal.Notify(sigs, os.Interrupt, syscall.SIGTERM) signal.Notify(sigs, os.Interrupt, syscall.SIGTERM)
sig := <-sigs sig := <-sigs
log.Infof("received signal %s, shutting down", sig) log.Infof(ctx, "received signal %s, shutting down", sig)
testrig.StandardDBTeardown(dbService) testrig.StandardDBTeardown(dbService)
testrig.StandardStorageTeardown(storageBackend) testrig.StandardStorageTeardown(storageBackend)
@ -165,6 +165,6 @@
return fmt.Errorf("error closing gotosocial service: %s", err) return fmt.Errorf("error closing gotosocial service: %s", err)
} }
log.Info("done! exiting...") log.Info(ctx, "done! exiting...")
return nil return nil
} }

View file

@ -0,0 +1,16 @@
# Observability
These settings let you tune and configure certain observability related behaviours.
## Settings
```yaml
##################################
##### OBSERVABILITY SETTINGS #####
##################################
# String. Header name to use to extract a request or trace ID from. Typically set by a
# loadbalancer or proxy.
# Default: "X-Request-Id"
request-id-header: "X-Request-Id"
```

View file

@ -692,6 +692,15 @@ syslog-protocol: "udp"
# Default: "localhost:514" # Default: "localhost:514"
syslog-address: "localhost:514" syslog-address: "localhost:514"
##################################
##### OBSERVABILITY SETTINGS #####
##################################
# String. Header name to use to extract a request or trace ID from. Typically set by a
# loadbalancer or proxy.
# Default: "X-Request-Id"
request-id-header: "X-Request-Id"
############################# #############################
##### ADVANCED SETTINGS ##### ##### ADVANCED SETTINGS #####
############################# #############################

View file

@ -100,7 +100,7 @@ func (suite *MediaCreateTestSuite) SetupSuite() {
func (suite *MediaCreateTestSuite) TearDownSuite() { func (suite *MediaCreateTestSuite) TearDownSuite() {
if err := suite.db.Stop(context.Background()); err != nil { if err := suite.db.Stop(context.Background()); err != nil {
log.Panicf("error closing db connection: %s", err) log.Panicf(nil, "error closing db connection: %s", err)
} }
} }

View file

@ -98,7 +98,7 @@ func (suite *MediaUpdateTestSuite) SetupSuite() {
func (suite *MediaUpdateTestSuite) TearDownSuite() { func (suite *MediaUpdateTestSuite) TearDownSuite() {
if err := suite.db.Stop(context.Background()); err != nil { if err := suite.db.Stop(context.Background()); err != nil {
log.Panicf("error closing db connection: %s", err) log.Panicf(nil, "error closing db connection: %s", err)
} }
} }

View file

@ -166,11 +166,12 @@ func (m *Module) StreamGETHandler(c *gin.Context) {
return return
} }
l := log.WithFields(kv.Fields{ l := log.WithContext(c.Request.Context()).
{"account", account.Username}, WithFields(kv.Fields{
{"streamID", stream.ID}, {"account", account.Username},
{"streamType", streamType}, {"streamID", stream.ID},
}...) {"streamType", streamType},
}...)
// Upgrade the incoming HTTP request, which hijacks the underlying // Upgrade the incoming HTTP request, which hijacks the underlying
// connection and reuses it for the websocket (non-http) protocol. // connection and reuses it for the websocket (non-http) protocol.

View file

@ -99,7 +99,7 @@ func (suite *FileserverTestSuite) SetupTest() {
func (suite *FileserverTestSuite) TearDownSuite() { func (suite *FileserverTestSuite) TearDownSuite() {
if err := suite.db.Stop(context.Background()); err != nil { if err := suite.db.Stop(context.Background()); err != nil {
log.Panicf("error closing db connection: %s", err) log.Panicf(nil, "error closing db connection: %s", err)
} }
} }

View file

@ -77,7 +77,10 @@ func (m *Module) ServeFile(c *gin.Context) {
return return
} }
content, errWithCode := m.processor.FileGet(c.Request.Context(), authed, &apimodel.GetContentRequestForm{ // Acquire context from gin request.
ctx := c.Request.Context()
content, errWithCode := m.processor.FileGet(ctx, authed, &apimodel.GetContentRequestForm{
AccountID: accountID, AccountID: accountID,
MediaType: mediaType, MediaType: mediaType,
MediaSize: mediaSize, MediaSize: mediaSize,
@ -101,7 +104,7 @@ func (m *Module) ServeFile(c *gin.Context) {
defer func() { defer func() {
// Close content when we're done, catch errors. // Close content when we're done, catch errors.
if err := content.Content.Close(); err != nil { if err := content.Content.Close(); err != nil {
log.Errorf("ServeFile: error closing readcloser: %s", err) log.Errorf(ctx, "ServeFile: error closing readcloser: %s", err)
} }
}() }()
@ -130,15 +133,21 @@ func (m *Module) ServeFile(c *gin.Context) {
return return
} }
// Set known content-type and serve this file range. // Set known content-type and serve range.
c.Header("Content-Type", format) c.Header("Content-Type", format)
serveFileRange(c.Writer, content.Content, rng, content.ContentLength) serveFileRange(
c.Writer,
c.Request,
content.Content,
rng,
content.ContentLength,
)
} }
// serveFileRange serves the range of a file from a given source reader, without the // serveFileRange serves the range of a file from a given source reader, without the
// need for implementation of io.Seeker. Instead we read the first 'start' many bytes // need for implementation of io.Seeker. Instead we read the first 'start' many bytes
// into a discard reader. Code is adapted from https://codeberg.org/gruf/simplehttp. // into a discard reader. Code is adapted from https://codeberg.org/gruf/simplehttp.
func serveFileRange(rw http.ResponseWriter, src io.Reader, rng string, size int64) { func serveFileRange(rw http.ResponseWriter, r *http.Request, src io.Reader, rng string, size int64) {
var i int var i int
if i = strings.IndexByte(rng, '='); i < 0 { if i = strings.IndexByte(rng, '='); i < 0 {
@ -219,7 +228,7 @@ func serveFileRange(rw http.ResponseWriter, src io.Reader, rng string, size int6
// Dump the first 'start' many bytes into the void... // Dump the first 'start' many bytes into the void...
if _, err := fastcopy.CopyN(io.Discard, src, start); err != nil { if _, err := fastcopy.CopyN(io.Discard, src, start); err != nil {
log.Errorf("error reading from source: %v", err) log.Errorf(r.Context(), "error reading from source: %v", err)
return return
} }
@ -239,7 +248,7 @@ func serveFileRange(rw http.ResponseWriter, src io.Reader, rng string, size int6
// Read the "seeked" source reader into destination writer. // Read the "seeked" source reader into destination writer.
if _, err := fastcopy.Copy(rw, src); err != nil { if _, err := fastcopy.Copy(rw, src); err != nil {
log.Errorf("error reading from source: %v", err) log.Errorf(r.Context(), "error reading from source: %v", err)
return return
} }
} }

View file

@ -27,6 +27,7 @@
apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model" apimodel "github.com/superseriousbusiness/gotosocial/internal/api/model"
"github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/log" "github.com/superseriousbusiness/gotosocial/internal/log"
"github.com/superseriousbusiness/gotosocial/internal/middleware"
) )
// TODO: add more templated html pages here for different error types // TODO: add more templated html pages here for different error types
@ -43,16 +44,20 @@
func NotFoundHandler(c *gin.Context, instanceGet func(ctx context.Context) (*apimodel.InstanceV1, gtserror.WithCode), accept string) { func NotFoundHandler(c *gin.Context, instanceGet func(ctx context.Context) (*apimodel.InstanceV1, gtserror.WithCode), accept string) {
switch accept { switch accept {
case string(TextHTML): case string(TextHTML):
instance, err := instanceGet(c.Request.Context()) ctx := c.Request.Context()
instance, err := instanceGet(ctx)
if err != nil { if err != nil {
panic(err) panic(err)
} }
c.HTML(http.StatusNotFound, "404.tmpl", gin.H{ c.HTML(http.StatusNotFound, "404.tmpl", gin.H{
"instance": instance, "instance": instance,
"requestID": middleware.RequestID(ctx),
}) })
default: default:
c.JSON(http.StatusNotFound, gin.H{"error": http.StatusText(http.StatusNotFound)}) c.JSON(http.StatusNotFound, gin.H{
"error": http.StatusText(http.StatusNotFound),
})
} }
} }
@ -62,15 +67,17 @@ func NotFoundHandler(c *gin.Context, instanceGet func(ctx context.Context) (*api
func genericErrorHandler(c *gin.Context, instanceGet func(ctx context.Context) (*apimodel.InstanceV1, gtserror.WithCode), accept string, errWithCode gtserror.WithCode) { func genericErrorHandler(c *gin.Context, instanceGet func(ctx context.Context) (*apimodel.InstanceV1, gtserror.WithCode), accept string, errWithCode gtserror.WithCode) {
switch accept { switch accept {
case string(TextHTML): case string(TextHTML):
instance, err := instanceGet(c.Request.Context()) ctx := c.Request.Context()
instance, err := instanceGet(ctx)
if err != nil { if err != nil {
panic(err) panic(err)
} }
c.HTML(errWithCode.Code(), "error.tmpl", gin.H{ c.HTML(errWithCode.Code(), "error.tmpl", gin.H{
"instance": instance, "instance": instance,
"code": errWithCode.Code(), "code": errWithCode.Code(),
"error": errWithCode.Safe(), "error": errWithCode.Safe(),
"requestID": middleware.RequestID(ctx),
}) })
default: default:
c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()}) c.JSON(errWithCode.Code(), gin.H{"error": errWithCode.Safe()})
@ -108,11 +115,12 @@ func ErrorHandler(c *gin.Context, errWithCode gtserror.WithCode, instanceGet fun
// to pass any detailed errors (that might contain sensitive information) into the // to pass any detailed errors (that might contain sensitive information) into the
// errWithCode.Error() field, since the client will see this. Use your noggin! // errWithCode.Error() field, since the client will see this. Use your noggin!
func OAuthErrorHandler(c *gin.Context, errWithCode gtserror.WithCode) { func OAuthErrorHandler(c *gin.Context, errWithCode gtserror.WithCode) {
l := log.WithFields(kv.Fields{ l := log.WithContext(c.Request.Context()).
{"path", c.Request.URL.Path}, WithFields(kv.Fields{
{"error", errWithCode.Error()}, {"path", c.Request.URL.Path},
{"help", errWithCode.Safe()}, {"error", errWithCode.Error()},
}...) {"help", errWithCode.Safe()},
}...)
statusCode := errWithCode.Code() statusCode := errWithCode.Code()

View file

@ -35,5 +35,5 @@ func tryUntil(msg string, count int, do func() bool) {
return return
} }
} }
log.Panicf("failed %s after %d tries", msg, count) log.Panicf(nil, "failed %s after %d tries", msg, count)
} }

View file

@ -66,7 +66,7 @@ func NewWorkerPool[MsgType any](workers int, queueRatio int) *WorkerPool[MsgType
} }
// Log new worker creation with worker type prefix // Log new worker creation with worker type prefix
log.Infof("%s created with workers=%d queue=%d", log.Infof(nil, "%s created with workers=%d queue=%d",
w.wtype, w.wtype,
workers, workers,
workers*queueRatio, workers*queueRatio,
@ -77,7 +77,7 @@ func NewWorkerPool[MsgType any](workers int, queueRatio int) *WorkerPool[MsgType
// Start will attempt to start the underlying worker pool, or return error. // Start will attempt to start the underlying worker pool, or return error.
func (w *WorkerPool[MsgType]) Start() error { func (w *WorkerPool[MsgType]) Start() error {
log.Infof("%s starting", w.wtype) log.Infof(nil, "%s starting", w.wtype)
// Check processor was set // Check processor was set
if w.process == nil { if w.process == nil {
@ -94,7 +94,7 @@ func (w *WorkerPool[MsgType]) Start() error {
// Stop will attempt to stop the underlying worker pool, or return error. // Stop will attempt to stop the underlying worker pool, or return error.
func (w *WorkerPool[MsgType]) Stop() error { func (w *WorkerPool[MsgType]) Stop() error {
log.Infof("%s stopping", w.wtype) log.Infof(nil, "%s stopping", w.wtype)
// Attempt to stop pool // Attempt to stop pool
if !w.workers.Stop() { if !w.workers.Stop() {
@ -107,14 +107,14 @@ func (w *WorkerPool[MsgType]) Stop() error {
// SetProcessor will set the Worker's processor function, which is called for each queued message. // SetProcessor will set the Worker's processor function, which is called for each queued message.
func (w *WorkerPool[MsgType]) SetProcessor(fn func(context.Context, MsgType) error) { func (w *WorkerPool[MsgType]) SetProcessor(fn func(context.Context, MsgType) error) {
if w.process != nil { if w.process != nil {
log.Panicf("%s Worker.process is already set", w.wtype) log.Panicf(nil, "%s Worker.process is already set", w.wtype)
} }
w.process = fn w.process = fn
} }
// Queue will queue provided message to be processed with there's a free worker. // Queue will queue provided message to be processed with there's a free worker.
func (w *WorkerPool[MsgType]) Queue(msg MsgType) { func (w *WorkerPool[MsgType]) Queue(msg MsgType) {
log.Tracef("%s queueing message: %+v", w.wtype, msg) log.Tracef(nil, "%s queueing message: %+v", w.wtype, msg)
// Create new process function for msg // Create new process function for msg
process := func(ctx context.Context) { process := func(ctx context.Context) {

View file

@ -147,6 +147,8 @@ type Configuration struct {
AdminAccountPassword string `name:"password" usage:"the password to set for this account"` AdminAccountPassword string `name:"password" usage:"the password to set for this account"`
AdminTransPath string `name:"path" usage:"the path of the file to import from/export to"` AdminTransPath string `name:"path" usage:"the path of the file to import from/export to"`
AdminMediaPruneDryRun bool `name:"dry-run" usage:"perform a dry run and only log number of items eligible for pruning"` AdminMediaPruneDryRun bool `name:"dry-run" usage:"perform a dry run and only log number of items eligible for pruning"`
RequestIDHeader string `name:"request-id-header" usage:"Header to extract the Request ID from. Eg.,'X-Request-Id'"`
} }
type CacheConfiguration struct { type CacheConfiguration struct {

View file

@ -163,4 +163,6 @@
}, },
AdminMediaPruneDryRun: true, AdminMediaPruneDryRun: true,
RequestIDHeader: "X-Request-Id",
} }

View file

@ -140,6 +140,8 @@ func (s *ConfigState) AddServerFlags(cmd *cobra.Command) {
cmd.Flags().Int(AdvancedRateLimitRequestsFlag(), cfg.AdvancedRateLimitRequests, fieldtag("AdvancedRateLimitRequests", "usage")) cmd.Flags().Int(AdvancedRateLimitRequestsFlag(), cfg.AdvancedRateLimitRequests, fieldtag("AdvancedRateLimitRequests", "usage"))
cmd.Flags().Int(AdvancedThrottlingMultiplierFlag(), cfg.AdvancedThrottlingMultiplier, fieldtag("AdvancedThrottlingMultiplier", "usage")) cmd.Flags().Int(AdvancedThrottlingMultiplierFlag(), cfg.AdvancedThrottlingMultiplier, fieldtag("AdvancedThrottlingMultiplier", "usage"))
cmd.Flags().Duration(AdvancedThrottlingRetryAfterFlag(), cfg.AdvancedThrottlingRetryAfter, fieldtag("AdvancedThrottlingRetryAfter", "usage")) cmd.Flags().Duration(AdvancedThrottlingRetryAfterFlag(), cfg.AdvancedThrottlingRetryAfter, fieldtag("AdvancedThrottlingRetryAfter", "usage"))
cmd.Flags().String(RequestIDHeaderFlag(), cfg.RequestIDHeader, fieldtag("RequestIDHeader", "usage"))
}) })
} }

View file

@ -2977,3 +2977,28 @@ func GetAdminMediaPruneDryRun() bool { return global.GetAdminMediaPruneDryRun()
// SetAdminMediaPruneDryRun safely sets the value for global configuration 'AdminMediaPruneDryRun' field // SetAdminMediaPruneDryRun safely sets the value for global configuration 'AdminMediaPruneDryRun' field
func SetAdminMediaPruneDryRun(v bool) { global.SetAdminMediaPruneDryRun(v) } func SetAdminMediaPruneDryRun(v bool) { global.SetAdminMediaPruneDryRun(v) }
// GetRequestIDHeader safely fetches the Configuration value for state's 'RequestIDHeader' field
func (st *ConfigState) GetRequestIDHeader() (v string) {
st.mutex.Lock()
v = st.config.RequestIDHeader
st.mutex.Unlock()
return
}
// SetRequestIDHeader safely sets the Configuration value for state's 'RequestIDHeader' field
func (st *ConfigState) SetRequestIDHeader(v string) {
st.mutex.Lock()
defer st.mutex.Unlock()
st.config.RequestIDHeader = v
st.reloadToViper()
}
// RequestIDHeaderFlag returns the flag name for the 'RequestIDHeader' field
func RequestIDHeaderFlag() string { return "request-id-header" }
// GetRequestIDHeader safely fetches the value for global configuration 'RequestIDHeader' field
func GetRequestIDHeader() string { return global.GetRequestIDHeader() }
// SetRequestIDHeader safely sets the value for global configuration 'RequestIDHeader' field
func SetRequestIDHeader(v string) { global.SetRequestIDHeader(v) }

View file

@ -416,3 +416,12 @@ cache:
account-max-size: 99 account-max-size: 99
account-ttl: "3h" account-ttl: "3h"
account-sweep-freq: "1s" account-sweep-freq: "1s"
##################################
##### OBSERVABILITY SETTINGS #####
##################################
# String. Header name to use to extract a request or trace ID from. Typically set by a
# loadbalancer or proxy.
# Default: "X-Request-Id"
request-id-header: "X-Trace-Id"

View file

@ -55,7 +55,7 @@ func Validate() error {
// no problem // no problem
break break
case "http": case "http":
log.Warnf("%s was set to 'http'; this should *only* be used for debugging and tests!", ProtocolFlag()) log.Warnf(nil, "%s was set to 'http'; this should *only* be used for debugging and tests!", ProtocolFlag())
case "": case "":
errs = append(errs, fmt.Errorf("%s must be set", ProtocolFlag())) errs = append(errs, fmt.Errorf("%s must be set", ProtocolFlag()))
default: default:

View file

@ -146,7 +146,7 @@ func (a *accountDB) getAccount(ctx context.Context, lookup string, dbQuery func(
// Set the account's related avatar // Set the account's related avatar
account.AvatarMediaAttachment, err = a.state.DB.GetAttachmentByID(ctx, account.AvatarMediaAttachmentID) account.AvatarMediaAttachment, err = a.state.DB.GetAttachmentByID(ctx, account.AvatarMediaAttachmentID)
if err != nil { if err != nil {
log.Errorf("error getting account %s avatar: %v", account.ID, err) log.Errorf(ctx, "error getting account %s avatar: %v", account.ID, err)
} }
} }
@ -154,7 +154,7 @@ func (a *accountDB) getAccount(ctx context.Context, lookup string, dbQuery func(
// Set the account's related header // Set the account's related header
account.HeaderMediaAttachment, err = a.state.DB.GetAttachmentByID(ctx, account.HeaderMediaAttachmentID) account.HeaderMediaAttachment, err = a.state.DB.GetAttachmentByID(ctx, account.HeaderMediaAttachmentID)
if err != nil { if err != nil {
log.Errorf("error getting account %s header: %v", account.ID, err) log.Errorf(ctx, "error getting account %s header: %v", account.ID, err)
} }
} }
@ -162,7 +162,7 @@ func (a *accountDB) getAccount(ctx context.Context, lookup string, dbQuery func(
// Set the account's related emojis // Set the account's related emojis
account.Emojis, err = a.state.DB.GetEmojisByIDs(ctx, account.EmojiIDs) account.Emojis, err = a.state.DB.GetEmojisByIDs(ctx, account.EmojiIDs)
if err != nil { if err != nil {
log.Errorf("error getting account %s emojis: %v", account.ID, err) log.Errorf(ctx, "error getting account %s emojis: %v", account.ID, err)
} }
} }
@ -412,7 +412,7 @@ func (a *accountDB) GetAccountStatuses(ctx context.Context, accountID string, li
Where("? != '{}'", bun.Ident("status.attachments")). Where("? != '{}'", bun.Ident("status.attachments")).
Where("? != '[]'", bun.Ident("status.attachments")) Where("? != '[]'", bun.Ident("status.attachments"))
default: default:
log.Panic("db dialect was neither pg nor sqlite") log.Panic(ctx, "db dialect was neither pg nor sqlite")
return q return q
} }
}) })
@ -540,7 +540,7 @@ func (a *accountDB) statusesFromIDs(ctx context.Context, statusIDs []string) ([]
// Fetch from status from database by ID // Fetch from status from database by ID
status, err := a.state.DB.GetStatusByID(ctx, id) status, err := a.state.DB.GetStatusByID(ctx, id)
if err != nil { if err != nil {
log.Errorf("statusesFromIDs: error getting status %q: %v", id, err) log.Errorf(ctx, "error getting status %q: %v", id, err)
continue continue
} }

View file

@ -93,7 +93,7 @@ func (a *adminDB) IsEmailAvailable(ctx context.Context, email string) (bool, db.
func (a *adminDB) NewSignup(ctx context.Context, username string, reason string, requireApproval bool, email string, password string, signUpIP net.IP, locale string, appID string, emailVerified bool, externalID string, admin bool) (*gtsmodel.User, db.Error) { func (a *adminDB) NewSignup(ctx context.Context, username string, reason string, requireApproval bool, email string, password string, signUpIP net.IP, locale string, appID string, emailVerified bool, externalID string, admin bool) (*gtsmodel.User, db.Error) {
key, err := rsa.GenerateKey(rand.Reader, rsaKeyBits) key, err := rsa.GenerateKey(rand.Reader, rsaKeyBits)
if err != nil { if err != nil {
log.Errorf("error creating new rsa key: %s", err) log.Errorf(ctx, "error creating new rsa key: %s", err)
return nil, err return nil, err
} }
@ -107,7 +107,7 @@ func (a *adminDB) NewSignup(ctx context.Context, username string, reason string,
Scan(ctx); err != nil { Scan(ctx); err != nil {
err = a.conn.ProcessError(err) err = a.conn.ProcessError(err)
if err != db.ErrNoEntries { if err != db.ErrNoEntries {
log.Errorf("error checking for existing account: %s", err) log.Errorf(ctx, "error checking for existing account: %s", err)
return nil, err return nil, err
} }
@ -207,13 +207,13 @@ func (a *adminDB) CreateInstanceAccount(ctx context.Context) db.Error {
return err return err
} }
if exists { if exists {
log.Infof("instance account %s already exists", username) log.Infof(ctx, "instance account %s already exists", username)
return nil return nil
} }
key, err := rsa.GenerateKey(rand.Reader, rsaKeyBits) key, err := rsa.GenerateKey(rand.Reader, rsaKeyBits)
if err != nil { if err != nil {
log.Errorf("error creating new rsa key: %s", err) log.Errorf(ctx, "error creating new rsa key: %s", err)
return err return err
} }
@ -245,7 +245,7 @@ func (a *adminDB) CreateInstanceAccount(ctx context.Context) db.Error {
return err return err
} }
log.Infof("instance account %s CREATED with id %s", username, acct.ID) log.Infof(ctx, "instance account %s CREATED with id %s", username, acct.ID)
return nil return nil
} }
@ -265,7 +265,7 @@ func (a *adminDB) CreateInstanceInstance(ctx context.Context) db.Error {
return err return err
} }
if exists { if exists {
log.Infof("instance entry already exists") log.Infof(ctx, "instance entry already exists")
return nil return nil
} }
@ -290,6 +290,6 @@ func (a *adminDB) CreateInstanceInstance(ctx context.Context) db.Error {
return a.conn.ProcessError(err) return a.conn.ProcessError(err)
} }
log.Infof("created instance instance %s with id %s", host, i.ID) log.Infof(ctx, "created instance instance %s with id %s", host, i.ID)
return nil return nil
} }

View file

@ -165,6 +165,6 @@ func (b *basicDB) IsHealthy(ctx context.Context) db.Error {
} }
func (b *basicDB) Stop(ctx context.Context) db.Error { func (b *basicDB) Stop(ctx context.Context) db.Error {
log.Info("closing db connection") log.Info(ctx, "closing db connection")
return b.conn.Close() return b.conn.Close()
} }

View file

@ -100,11 +100,11 @@ func doMigration(ctx context.Context, db *bun.DB) error {
} }
if group.ID == 0 { if group.ID == 0 {
log.Info("there are no new migrations to run") log.Info(ctx, "there are no new migrations to run")
return nil return nil
} }
log.Infof("MIGRATED DATABASE TO %s", group) log.Infof(ctx, "MIGRATED DATABASE TO %s", group)
return nil return nil
} }
@ -245,7 +245,7 @@ func pgConn(ctx context.Context) (*DBConn, error) {
return nil, fmt.Errorf("postgres ping: %s", err) return nil, fmt.Errorf("postgres ping: %s", err)
} }
log.Info("connected to POSTGRES database") log.Info(ctx, "connected to POSTGRES database")
return conn, nil return conn, nil
} }
@ -268,7 +268,7 @@ func sqliteConn(ctx context.Context) (*DBConn, error) {
} }
if address == ":memory:" { if address == ":memory:" {
log.Warn("using sqlite in-memory mode; all data will be deleted when gts shuts down; this mode should only be used for debugging or running tests") log.Warn(ctx, "using sqlite in-memory mode; all data will be deleted when gts shuts down; this mode should only be used for debugging or running tests")
// Use random name for in-memory instead of ':memory:', so // Use random name for in-memory instead of ':memory:', so
// multiple in-mem databases can be created without conflict. // multiple in-mem databases can be created without conflict.
@ -319,7 +319,7 @@ func sqliteConn(ctx context.Context) (*DBConn, error) {
} }
return nil, fmt.Errorf("sqlite ping: %s", err) return nil, fmt.Errorf("sqlite ping: %s", err)
} }
log.Infof("connected to SQLITE database with address %s", address) log.Infof(ctx, "connected to SQLITE database with address %s", address)
return conn, nil return conn, nil
} }
@ -464,7 +464,7 @@ func sqlitePragmas(ctx context.Context, conn *DBConn) error {
return fmt.Errorf("error scanning sqlite pragma %s: %w", pv, err) return fmt.Errorf("error scanning sqlite pragma %s: %w", pv, err)
} }
log.Infof("sqlite pragma %s set to %s", pk, res) log.Infof(ctx, "sqlite pragma %s set to %s", pk, res)
} }
return nil return nil

View file

@ -372,7 +372,7 @@ func (e *emojiDB) GetEmojisByIDs(ctx context.Context, emojiIDs []string) ([]*gts
for _, id := range emojiIDs { for _, id := range emojiIDs {
emoji, err := e.GetEmojiByID(ctx, id) emoji, err := e.GetEmojiByID(ctx, id)
if err != nil { if err != nil {
log.Errorf("emojisFromIDs: error getting emoji %q: %v", id, err) log.Errorf(ctx, "emojisFromIDs: error getting emoji %q: %v", id, err)
continue continue
} }
@ -405,7 +405,7 @@ func (e *emojiDB) GetEmojiCategoriesByIDs(ctx context.Context, emojiCategoryIDs
for _, id := range emojiCategoryIDs { for _, id := range emojiCategoryIDs {
emojiCategory, err := e.GetEmojiCategory(ctx, id) emojiCategory, err := e.GetEmojiCategory(ctx, id)
if err != nil { if err != nil {
log.Errorf("emojiCategoriesFromIDs: error getting emoji category %q: %v", id, err) log.Errorf(ctx, "error getting emoji category %q: %v", id, err)
continue continue
} }

View file

@ -36,17 +36,18 @@ func (queryHook) BeforeQuery(ctx context.Context, _ *bun.QueryEvent) context.Con
} }
// AfterQuery logs the time taken to query, the operation (select, update, etc), and the query itself as translated by bun. // AfterQuery logs the time taken to query, the operation (select, update, etc), and the query itself as translated by bun.
func (queryHook) AfterQuery(_ context.Context, event *bun.QueryEvent) { func (queryHook) AfterQuery(ctx context.Context, event *bun.QueryEvent) {
// Get the DB query duration // Get the DB query duration
dur := time.Since(event.StartTime) dur := time.Since(event.StartTime)
switch { switch {
// Warn on slow database queries // Warn on slow database queries
case dur > time.Second: case dur > time.Second:
log.WithFields(kv.Fields{ log.WithContext(ctx).
{"duration", dur}, WithFields(kv.Fields{
{"query", event.Query}, {"duration", dur},
}...).Warn("SLOW DATABASE QUERY") {"query", event.Query},
}...).Warn("SLOW DATABASE QUERY")
// On trace, we log query information, // On trace, we log query information,
// manually crafting so DB query not escaped. // manually crafting so DB query not escaped.

View file

@ -58,7 +58,7 @@ func (m *mediaDB) getAttachments(ctx context.Context, ids []string) ([]*gtsmodel
// Attempt fetch from DB // Attempt fetch from DB
attachment, err := m.GetAttachmentByID(ctx, id) attachment, err := m.GetAttachmentByID(ctx, id)
if err != nil { if err != nil {
log.Errorf("error getting attachment %q: %v", id, err) log.Errorf(ctx, "error getting attachment %q: %v", id, err)
continue continue
} }

View file

@ -64,7 +64,7 @@ func (m *mentionDB) GetMentions(ctx context.Context, ids []string) ([]*gtsmodel.
// Attempt fetch from DB // Attempt fetch from DB
mention, err := m.GetMention(ctx, id) mention, err := m.GetMention(ctx, id)
if err != nil { if err != nil {
log.Errorf("GetMentions: error getting mention %q: %v", id, err) log.Errorf(ctx, "error getting mention %q: %v", id, err)
continue continue
} }

View file

@ -38,7 +38,7 @@ func init() {
case dialect.SQLite: case dialect.SQLite:
q = q.ColumnExpr("? VARCHAR", bun.Ident("emojis")) q = q.ColumnExpr("? VARCHAR", bun.Ident("emojis"))
default: default:
log.Panic("db dialect was neither pg nor sqlite") log.Panic(ctx, "db dialect was neither pg nor sqlite")
} }
if _, err := q.Exec(ctx); err != nil { if _, err := q.Exec(ctx); err != nil {

View file

@ -94,7 +94,7 @@ func (n *notificationDB) GetNotifications(ctx context.Context, accountID string,
// Attempt fetch from DB // Attempt fetch from DB
notif, err := n.GetNotification(ctx, id) notif, err := n.GetNotification(ctx, id)
if err != nil { if err != nil {
log.Errorf("GetNotifications: error getting notification %q: %v", id, err) log.Errorf(ctx, "error getting notification %q: %v", id, err)
continue continue
} }

View file

@ -106,7 +106,7 @@ func (r *reportDB) GetReports(ctx context.Context, resolved *bool, accountID str
for _, id := range reportIDs { for _, id := range reportIDs {
report, err := r.GetReportByID(ctx, id) report, err := r.GetReportByID(ctx, id)
if err != nil { if err != nil {
log.Errorf("GetReports: error getting report %q: %v", id, err) log.Errorf(ctx, "error getting report %q: %v", id, err)
continue continue
} }

View file

@ -74,7 +74,7 @@ func (s *statusDB) GetStatuses(ctx context.Context, ids []string) ([]*gtsmodel.S
// Attempt fetch from DB // Attempt fetch from DB
status, err := s.GetStatusByID(ctx, id) status, err := s.GetStatusByID(ctx, id)
if err != nil { if err != nil {
log.Errorf("GetStatuses: error getting status %q: %v", id, err) log.Errorf(ctx, "error getting status %q: %v", id, err)
continue continue
} }
@ -387,7 +387,7 @@ func (s *statusDB) GetStatusChildren(ctx context.Context, status *gtsmodel.Statu
// only append children, not the overall parent status // only append children, not the overall parent status
entry, ok := e.Value.(*gtsmodel.Status) entry, ok := e.Value.(*gtsmodel.Status)
if !ok { if !ok {
log.Panic("GetStatusChildren: found status could not be asserted to *gtsmodel.Status") log.Panic(ctx, "found status could not be asserted to *gtsmodel.Status")
} }
if entry.ID != status.ID { if entry.ID != status.ID {
@ -412,7 +412,7 @@ func (s *statusDB) statusChildren(ctx context.Context, status *gtsmodel.Status,
if err := q.Scan(ctx, &childIDs); err != nil { if err := q.Scan(ctx, &childIDs); err != nil {
if err != sql.ErrNoRows { if err != sql.ErrNoRows {
log.Errorf("statusChildren: error getting children for %q: %v", status.ID, err) log.Errorf(ctx, "error getting children for %q: %v", status.ID, err)
} }
return return
} }
@ -421,7 +421,7 @@ func (s *statusDB) statusChildren(ctx context.Context, status *gtsmodel.Status,
// Fetch child with ID from database // Fetch child with ID from database
child, err := s.GetStatusByID(ctx, id) child, err := s.GetStatusByID(ctx, id)
if err != nil { if err != nil {
log.Errorf("statusChildren: error getting child status %q: %v", id, err) log.Errorf(ctx, "error getting child status %q: %v", id, err)
continue continue
} }
@ -429,7 +429,7 @@ func (s *statusDB) statusChildren(ctx context.Context, status *gtsmodel.Status,
for e := foundStatuses.Front(); e != nil; e = e.Next() { for e := foundStatuses.Front(); e != nil; e = e.Next() {
entry, ok := e.Value.(*gtsmodel.Status) entry, ok := e.Value.(*gtsmodel.Status)
if !ok { if !ok {
log.Panic("statusChildren: found status could not be asserted to *gtsmodel.Status") log.Panic(ctx, "found status could not be asserted to *gtsmodel.Status")
} }
if child.InReplyToAccountID != "" && entry.ID == child.InReplyToID { if child.InReplyToAccountID != "" && entry.ID == child.InReplyToID {

View file

@ -114,7 +114,7 @@ func (t *timelineDB) GetHomeTimeline(ctx context.Context, accountID string, maxI
// Fetch status from db for ID // Fetch status from db for ID
status, err := t.state.DB.GetStatusByID(ctx, id) status, err := t.state.DB.GetStatusByID(ctx, id)
if err != nil { if err != nil {
log.Errorf("GetHomeTimeline: error fetching status %q: %v", id, err) log.Errorf(ctx, "error fetching status %q: %v", id, err)
continue continue
} }
@ -182,7 +182,7 @@ func (t *timelineDB) GetPublicTimeline(ctx context.Context, maxID string, sinceI
// Fetch status from db for ID // Fetch status from db for ID
status, err := t.state.DB.GetStatusByID(ctx, id) status, err := t.state.DB.GetStatusByID(ctx, id)
if err != nil { if err != nil {
log.Errorf("GetPublicTimeline: error fetching status %q: %v", id, err) log.Errorf(ctx, "error fetching status %q: %v", id, err)
continue continue
} }
@ -242,7 +242,7 @@ func (t *timelineDB) GetFavedTimeline(ctx context.Context, accountID string, max
// Fetch status from db for corresponding favourite // Fetch status from db for corresponding favourite
status, err := t.state.DB.GetStatusByID(ctx, fave.StatusID) status, err := t.state.DB.GetStatusByID(ctx, fave.StatusID)
if err != nil { if err != nil {
log.Errorf("GetFavedTimeline: error fetching status for fave %q: %v", fave.ID, err) log.Errorf(ctx, "error fetching status for fave %q: %v", fave.ID, err)
continue continue
} }

View file

@ -42,7 +42,7 @@ func (s *sender) SendConfirmEmail(toAddress string, data ConfirmData) error {
if err != nil { if err != nil {
return err return err
} }
log.Trace(s.hostAddress + "\n" + config.GetSMTPUsername() + ":password" + "\n" + s.from + "\n" + toAddress + "\n\n" + string(msg) + "\n") log.Trace(nil, s.hostAddress+"\n"+config.GetSMTPUsername()+":password"+"\n"+s.from+"\n"+toAddress+"\n\n"+string(msg)+"\n")
return smtp.SendMail(s.hostAddress, s.auth, s.from, []string{toAddress}, msg) return smtp.SendMail(s.hostAddress, s.auth, s.from, []string{toAddress}, msg)
} }

View file

@ -61,7 +61,7 @@ func (s *noopSender) SendConfirmEmail(toAddress string, data ConfirmData) error
return err return err
} }
log.Tracef("NOT SENDING confirmation email to %s with contents: %s", toAddress, msg) log.Tracef(nil, "NOT SENDING confirmation email to %s with contents: %s", toAddress, msg)
if s.sendCallback != nil { if s.sendCallback != nil {
s.sendCallback(toAddress, string(msg)) s.sendCallback(toAddress, string(msg))
@ -81,7 +81,7 @@ func (s *noopSender) SendResetEmail(toAddress string, data ResetData) error {
return err return err
} }
log.Tracef("NOT SENDING reset email to %s with contents: %s", toAddress, msg) log.Tracef(nil, "NOT SENDING reset email to %s with contents: %s", toAddress, msg)
if s.sendCallback != nil { if s.sendCallback != nil {
s.sendCallback(toAddress, string(msg)) s.sendCallback(toAddress, string(msg))

View file

@ -124,7 +124,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
if vi == nil { if vi == nil {
err := errors.New("http request wasn't signed or http signature was invalid") err := errors.New("http request wasn't signed or http signature was invalid")
errWithCode := gtserror.NewErrorUnauthorized(err, err.Error()) errWithCode := gtserror.NewErrorUnauthorized(err, err.Error())
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
@ -132,7 +132,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
if !ok { if !ok {
err := errors.New("http request wasn't signed or http signature was invalid") err := errors.New("http request wasn't signed or http signature was invalid")
errWithCode := gtserror.NewErrorUnauthorized(err, err.Error()) errWithCode := gtserror.NewErrorUnauthorized(err, err.Error())
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
@ -141,7 +141,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
if si == nil { if si == nil {
err := errors.New("http request wasn't signed or http signature was invalid") err := errors.New("http request wasn't signed or http signature was invalid")
errWithCode := gtserror.NewErrorUnauthorized(err, err.Error()) errWithCode := gtserror.NewErrorUnauthorized(err, err.Error())
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
@ -149,7 +149,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
if !ok { if !ok {
err := errors.New("http request wasn't signed or http signature was invalid") err := errors.New("http request wasn't signed or http signature was invalid")
errWithCode := gtserror.NewErrorUnauthorized(err, err.Error()) errWithCode := gtserror.NewErrorUnauthorized(err, err.Error())
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
@ -157,7 +157,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
requestingPublicKeyID, err := url.Parse(verifier.KeyId()) requestingPublicKeyID, err := url.Parse(verifier.KeyId())
if err != nil { if err != nil {
errWithCode := gtserror.NewErrorBadRequest(err, fmt.Sprintf("couldn't parse public key URL %s", verifier.KeyId())) errWithCode := gtserror.NewErrorBadRequest(err, fmt.Sprintf("couldn't parse public key URL %s", verifier.KeyId()))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
@ -170,12 +170,12 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
if host := config.GetHost(); strings.EqualFold(requestingHost, host) { if host := config.GetHost(); strings.EqualFold(requestingHost, host) {
// LOCAL ACCOUNT REQUEST // LOCAL ACCOUNT REQUEST
// the request is coming from INSIDE THE HOUSE so skip the remote dereferencing // the request is coming from INSIDE THE HOUSE so skip the remote dereferencing
log.Tracef("proceeding without dereference for local public key %s", requestingPublicKeyID) log.Tracef(ctx, "proceeding without dereference for local public key %s", requestingPublicKeyID)
requestingLocalAccount, err = f.db.GetAccountByPubkeyID(ctx, requestingPublicKeyID.String()) requestingLocalAccount, err = f.db.GetAccountByPubkeyID(ctx, requestingPublicKeyID.String())
if err != nil { if err != nil {
errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("couldn't get account with public key uri %s from the database: %s", requestingPublicKeyID.String(), err)) errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("couldn't get account with public key uri %s from the database: %s", requestingPublicKeyID.String(), err))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
@ -184,18 +184,18 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
pkOwnerURI, err = url.Parse(requestingLocalAccount.URI) pkOwnerURI, err = url.Parse(requestingLocalAccount.URI)
if err != nil { if err != nil {
errWithCode := gtserror.NewErrorBadRequest(err, fmt.Sprintf("couldn't parse public key owner URL %s", requestingLocalAccount.URI)) errWithCode := gtserror.NewErrorBadRequest(err, fmt.Sprintf("couldn't parse public key owner URL %s", requestingLocalAccount.URI))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
} else if requestingRemoteAccount, err = f.db.GetAccountByPubkeyID(ctx, requestingPublicKeyID.String()); err == nil { } else if requestingRemoteAccount, err = f.db.GetAccountByPubkeyID(ctx, requestingPublicKeyID.String()); err == nil {
// REMOTE ACCOUNT REQUEST WITH KEY CACHED LOCALLY // REMOTE ACCOUNT REQUEST WITH KEY CACHED LOCALLY
// this is a remote account and we already have the public key for it so use that // this is a remote account and we already have the public key for it so use that
log.Tracef("proceeding without dereference for cached public key %s", requestingPublicKeyID) log.Tracef(ctx, "proceeding without dereference for cached public key %s", requestingPublicKeyID)
publicKey = requestingRemoteAccount.PublicKey publicKey = requestingRemoteAccount.PublicKey
pkOwnerURI, err = url.Parse(requestingRemoteAccount.URI) pkOwnerURI, err = url.Parse(requestingRemoteAccount.URI)
if err != nil { if err != nil {
errWithCode := gtserror.NewErrorBadRequest(err, fmt.Sprintf("couldn't parse public key owner URL %s", requestingRemoteAccount.URI)) errWithCode := gtserror.NewErrorBadRequest(err, fmt.Sprintf("couldn't parse public key owner URL %s", requestingRemoteAccount.URI))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
} else { } else {
@ -205,21 +205,21 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
gone, err := f.CheckGone(ctx, requestingPublicKeyID) gone, err := f.CheckGone(ctx, requestingPublicKeyID)
if err != nil { if err != nil {
errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("error checking for tombstone for %s: %s", requestingPublicKeyID, err)) errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("error checking for tombstone for %s: %s", requestingPublicKeyID, err))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
if gone { if gone {
errWithCode := gtserror.NewErrorGone(fmt.Errorf("account with public key %s is gone", requestingPublicKeyID)) errWithCode := gtserror.NewErrorGone(fmt.Errorf("account with public key %s is gone", requestingPublicKeyID))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
log.Tracef("proceeding with dereference for uncached public key %s", requestingPublicKeyID) log.Tracef(ctx, "proceeding with dereference for uncached public key %s", requestingPublicKeyID)
trans, err := f.transportController.NewTransportForUsername(transport.WithFastfail(ctx), requestedUsername) trans, err := f.transportController.NewTransportForUsername(transport.WithFastfail(ctx), requestedUsername)
if err != nil { if err != nil {
errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("error creating transport for %s: %s", requestedUsername, err)) errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("error creating transport for %s: %s", requestedUsername, err))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
@ -231,16 +231,16 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
// we should add a tombstone to our database so that we can avoid trying to deref it in future // we should add a tombstone to our database so that we can avoid trying to deref it in future
if err := f.HandleGone(ctx, requestingPublicKeyID); err != nil { if err := f.HandleGone(ctx, requestingPublicKeyID); err != nil {
errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("error marking account with public key %s as gone: %s", requestingPublicKeyID, err)) errWithCode := gtserror.NewErrorInternalError(fmt.Errorf("error marking account with public key %s as gone: %s", requestingPublicKeyID, err))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
errWithCode := gtserror.NewErrorGone(fmt.Errorf("account with public key %s is gone", requestingPublicKeyID)) errWithCode := gtserror.NewErrorGone(fmt.Errorf("account with public key %s is gone", requestingPublicKeyID))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("error dereferencing public key %s: %s", requestingPublicKeyID, err)) errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("error dereferencing public key %s: %s", requestingPublicKeyID, err))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
@ -248,7 +248,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
requestingPublicKey, err := getPublicKeyFromResponse(ctx, b, requestingPublicKeyID) requestingPublicKey, err := getPublicKeyFromResponse(ctx, b, requestingPublicKeyID)
if err != nil { if err != nil {
errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("error parsing public key %s: %s", requestingPublicKeyID, err)) errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("error parsing public key %s: %s", requestingPublicKeyID, err))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
@ -256,7 +256,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
pkPemProp := requestingPublicKey.GetW3IDSecurityV1PublicKeyPem() pkPemProp := requestingPublicKey.GetW3IDSecurityV1PublicKeyPem()
if pkPemProp == nil || !pkPemProp.IsXMLSchemaString() { if pkPemProp == nil || !pkPemProp.IsXMLSchemaString() {
errWithCode := gtserror.NewErrorUnauthorized(errors.New("publicKeyPem property is not provided or it is not embedded as a value")) errWithCode := gtserror.NewErrorUnauthorized(errors.New("publicKeyPem property is not provided or it is not embedded as a value"))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
@ -265,14 +265,14 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
block, _ := pem.Decode([]byte(pubKeyPem)) block, _ := pem.Decode([]byte(pubKeyPem))
if block == nil || block.Type != "PUBLIC KEY" { if block == nil || block.Type != "PUBLIC KEY" {
errWithCode := gtserror.NewErrorUnauthorized(errors.New("could not decode publicKeyPem to PUBLIC KEY pem block type")) errWithCode := gtserror.NewErrorUnauthorized(errors.New("could not decode publicKeyPem to PUBLIC KEY pem block type"))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
publicKey, err = x509.ParsePKIXPublicKey(block.Bytes) publicKey, err = x509.ParsePKIXPublicKey(block.Bytes)
if err != nil { if err != nil {
errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("could not parse public key %s from block bytes: %s", requestingPublicKeyID, err)) errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("could not parse public key %s from block bytes: %s", requestingPublicKeyID, err))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
@ -280,7 +280,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
pkOwnerProp := requestingPublicKey.GetW3IDSecurityV1Owner() pkOwnerProp := requestingPublicKey.GetW3IDSecurityV1Owner()
if pkOwnerProp == nil || !pkOwnerProp.IsIRI() { if pkOwnerProp == nil || !pkOwnerProp.IsIRI() {
errWithCode := gtserror.NewErrorUnauthorized(errors.New("publicKeyOwner property is not provided or it is not embedded as a value")) errWithCode := gtserror.NewErrorUnauthorized(errors.New("publicKeyOwner property is not provided or it is not embedded as a value"))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
pkOwnerURI = pkOwnerProp.GetIRI() pkOwnerURI = pkOwnerProp.GetIRI()
@ -289,7 +289,7 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
// after all that, public key should be defined // after all that, public key should be defined
if publicKey == nil { if publicKey == nil {
errWithCode := gtserror.NewErrorInternalError(errors.New("returned public key was empty")) errWithCode := gtserror.NewErrorInternalError(errors.New("returned public key was empty"))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }
@ -301,16 +301,16 @@ func (f *federator) AuthenticateFederatedRequest(ctx context.Context, requestedU
} }
for _, algo := range algos { for _, algo := range algos {
log.Tracef("trying algo: %s", algo) log.Tracef(ctx, "trying algo: %s", algo)
err := verifier.Verify(publicKey, algo) err := verifier.Verify(publicKey, algo)
if err == nil { if err == nil {
log.Tracef("authentication for %s PASSED with algorithm %s", pkOwnerURI, algo) log.Tracef(ctx, "authentication for %s PASSED with algorithm %s", pkOwnerURI, algo)
return pkOwnerURI, nil return pkOwnerURI, nil
} }
log.Tracef("authentication for %s NOT PASSED with algorithm %s: %s", pkOwnerURI, algo, err) log.Tracef(ctx, "authentication for %s NOT PASSED with algorithm %s: %s", pkOwnerURI, algo, err)
} }
errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("authentication not passed for public key owner %s; signature value was '%s'", pkOwnerURI, signature)) errWithCode := gtserror.NewErrorUnauthorized(fmt.Errorf("authentication not passed for public key owner %s; signature value was '%s'", pkOwnerURI, signature))
log.Debug(errWithCode) log.Debug(ctx, errWithCode)
return nil, errWithCode return nil, errWithCode
} }

View file

@ -77,7 +77,7 @@ func (d *deref) GetAccountByURI(ctx context.Context, requestUser string, uri *ur
// Try to update existing account model // Try to update existing account model
enriched, err := d.enrichAccount(ctx, requestUser, uri, account, false, block) enriched, err := d.enrichAccount(ctx, requestUser, uri, account, false, block)
if err != nil { if err != nil {
log.Errorf("error enriching remote account: %v", err) log.Errorf(ctx, "error enriching remote account: %v", err)
return account, nil // fall back to returning existing return account, nil // fall back to returning existing
} }
@ -114,7 +114,7 @@ func (d *deref) GetAccountByUsernameDomain(ctx context.Context, requestUser stri
// Try to update existing account model // Try to update existing account model
enriched, err := d.enrichAccount(ctx, requestUser, nil, account, false, block) enriched, err := d.enrichAccount(ctx, requestUser, nil, account, false, block)
if err != nil { if err != nil {
log.Errorf("GetAccountByUsernameDomain: error enriching account from remote: %v", err) log.Errorf(ctx, "error enriching account from remote: %v", err)
return account, nil // fall back to returning unchanged existing account model return account, nil // fall back to returning unchanged existing account model
} }
@ -250,7 +250,7 @@ func (d *deref) enrichAccount(ctx context.Context, requestUser string, uri *url.
latestAcc.ID, latestAcc.ID,
) )
if err != nil { if err != nil {
log.Errorf("error fetching remote avatar for account %s: %v", uri, err) log.Errorf(ctx, "error fetching remote avatar for account %s: %v", uri, err)
// Keep old avatar for now, we'll try again in $interval. // Keep old avatar for now, we'll try again in $interval.
latestAcc.AvatarMediaAttachmentID = account.AvatarMediaAttachmentID latestAcc.AvatarMediaAttachmentID = account.AvatarMediaAttachmentID
@ -271,7 +271,7 @@ func (d *deref) enrichAccount(ctx context.Context, requestUser string, uri *url.
latestAcc.ID, latestAcc.ID,
) )
if err != nil { if err != nil {
log.Errorf("error fetching remote header for account %s: %v", uri, err) log.Errorf(ctx, "error fetching remote header for account %s: %v", uri, err)
// Keep old header for now, we'll try again in $interval. // Keep old header for now, we'll try again in $interval.
latestAcc.HeaderMediaAttachmentID = account.HeaderMediaAttachmentID latestAcc.HeaderMediaAttachmentID = account.HeaderMediaAttachmentID
@ -283,7 +283,7 @@ func (d *deref) enrichAccount(ctx context.Context, requestUser string, uri *url.
// Fetch the latest remote account emoji IDs used in account display name/bio. // Fetch the latest remote account emoji IDs used in account display name/bio.
_, err = d.fetchRemoteAccountEmojis(ctx, latestAcc, requestUser) _, err = d.fetchRemoteAccountEmojis(ctx, latestAcc, requestUser)
if err != nil { if err != nil {
log.Errorf("error fetching remote emojis for account %s: %v", uri, err) log.Errorf(ctx, "error fetching remote emojis for account %s: %v", uri, err)
} }
if account.CreatedAt.IsZero() { if account.CreatedAt.IsZero() {

View file

@ -111,7 +111,7 @@ func (d *deref) populateEmojis(ctx context.Context, rawEmojis []*gtsmodel.Emoji,
// have to get it from the database again // have to get it from the database again
gotEmoji = e gotEmoji = e
} else if gotEmoji, err = d.db.GetEmojiByShortcodeDomain(ctx, e.Shortcode, e.Domain); err != nil && err != db.ErrNoEntries { } else if gotEmoji, err = d.db.GetEmojiByShortcodeDomain(ctx, e.Shortcode, e.Domain); err != nil && err != db.ErrNoEntries {
log.Errorf("populateEmojis: error checking database for emoji %s: %s", shortcodeDomain, err) log.Errorf(ctx, "error checking database for emoji %s: %s", shortcodeDomain, err)
continue continue
} }
@ -120,24 +120,24 @@ func (d *deref) populateEmojis(ctx context.Context, rawEmojis []*gtsmodel.Emoji,
if gotEmoji != nil { if gotEmoji != nil {
// we had the emoji already, but refresh it if necessary // we had the emoji already, but refresh it if necessary
if e.UpdatedAt.Unix() > gotEmoji.ImageUpdatedAt.Unix() { if e.UpdatedAt.Unix() > gotEmoji.ImageUpdatedAt.Unix() {
log.Tracef("populateEmojis: emoji %s was updated since we last saw it, will refresh", shortcodeDomain) log.Tracef(ctx, "emoji %s was updated since we last saw it, will refresh", shortcodeDomain)
refresh = true refresh = true
} }
if !refresh && (e.URI != gotEmoji.URI) { if !refresh && (e.URI != gotEmoji.URI) {
log.Tracef("populateEmojis: emoji %s changed URI since we last saw it, will refresh", shortcodeDomain) log.Tracef(ctx, "emoji %s changed URI since we last saw it, will refresh", shortcodeDomain)
refresh = true refresh = true
} }
if !refresh && (e.ImageRemoteURL != gotEmoji.ImageRemoteURL) { if !refresh && (e.ImageRemoteURL != gotEmoji.ImageRemoteURL) {
log.Tracef("populateEmojis: emoji %s changed image URL since we last saw it, will refresh", shortcodeDomain) log.Tracef(ctx, "emoji %s changed image URL since we last saw it, will refresh", shortcodeDomain)
refresh = true refresh = true
} }
if !refresh { if !refresh {
log.Tracef("populateEmojis: emoji %s is up to date, will not refresh", shortcodeDomain) log.Tracef(ctx, "emoji %s is up to date, will not refresh", shortcodeDomain)
} else { } else {
log.Tracef("populateEmojis: refreshing emoji %s", shortcodeDomain) log.Tracef(ctx, "refreshing emoji %s", shortcodeDomain)
emojiID := gotEmoji.ID // use existing ID emojiID := gotEmoji.ID // use existing ID
processingEmoji, err := d.GetRemoteEmoji(ctx, requestingUsername, e.ImageRemoteURL, e.Shortcode, e.Domain, emojiID, e.URI, &media.AdditionalEmojiInfo{ processingEmoji, err := d.GetRemoteEmoji(ctx, requestingUsername, e.ImageRemoteURL, e.Shortcode, e.Domain, emojiID, e.URI, &media.AdditionalEmojiInfo{
Domain: &e.Domain, Domain: &e.Domain,
@ -147,12 +147,12 @@ func (d *deref) populateEmojis(ctx context.Context, rawEmojis []*gtsmodel.Emoji,
VisibleInPicker: gotEmoji.VisibleInPicker, VisibleInPicker: gotEmoji.VisibleInPicker,
}, refresh) }, refresh)
if err != nil { if err != nil {
log.Errorf("populateEmojis: couldn't refresh remote emoji %s: %s", shortcodeDomain, err) log.Errorf(ctx, "couldn't refresh remote emoji %s: %s", shortcodeDomain, err)
continue continue
} }
if gotEmoji, err = processingEmoji.LoadEmoji(ctx); err != nil { if gotEmoji, err = processingEmoji.LoadEmoji(ctx); err != nil {
log.Errorf("populateEmojis: couldn't load refreshed remote emoji %s: %s", shortcodeDomain, err) log.Errorf(ctx, "couldn't load refreshed remote emoji %s: %s", shortcodeDomain, err)
continue continue
} }
} }
@ -160,7 +160,7 @@ func (d *deref) populateEmojis(ctx context.Context, rawEmojis []*gtsmodel.Emoji,
// it's new! go get it! // it's new! go get it!
newEmojiID, err := id.NewRandomULID() newEmojiID, err := id.NewRandomULID()
if err != nil { if err != nil {
log.Errorf("populateEmojis: error generating id for remote emoji %s: %s", shortcodeDomain, err) log.Errorf(ctx, "error generating id for remote emoji %s: %s", shortcodeDomain, err)
continue continue
} }
@ -172,12 +172,12 @@ func (d *deref) populateEmojis(ctx context.Context, rawEmojis []*gtsmodel.Emoji,
VisibleInPicker: e.VisibleInPicker, VisibleInPicker: e.VisibleInPicker,
}, refresh) }, refresh)
if err != nil { if err != nil {
log.Errorf("populateEmojis: couldn't get remote emoji %s: %s", shortcodeDomain, err) log.Errorf(ctx, "couldn't get remote emoji %s: %s", shortcodeDomain, err)
continue continue
} }
if gotEmoji, err = processingEmoji.LoadEmoji(ctx); err != nil { if gotEmoji, err = processingEmoji.LoadEmoji(ctx); err != nil {
log.Errorf("populateEmojis: couldn't load remote emoji %s: %s", shortcodeDomain, err) log.Errorf(ctx, "couldn't load remote emoji %s: %s", shortcodeDomain, err)
continue continue
} }
} }

View file

@ -318,20 +318,20 @@ func (d *deref) populateStatusMentions(ctx context.Context, status *gtsmodel.Sta
for _, m := range status.Mentions { for _, m := range status.Mentions {
if m.ID != "" { if m.ID != "" {
// we've already populated this mention, since it has an ID // we've already populated this mention, since it has an ID
log.Debug("populateStatusMentions: mention already populated") log.Debug(ctx, "mention already populated")
mentionIDs = append(mentionIDs, m.ID) mentionIDs = append(mentionIDs, m.ID)
newMentions = append(newMentions, m) newMentions = append(newMentions, m)
continue continue
} }
if m.TargetAccountURI == "" { if m.TargetAccountURI == "" {
log.Debug("populateStatusMentions: target URI not set on mention") log.Debug(ctx, "target URI not set on mention")
continue continue
} }
targetAccountURI, err := url.Parse(m.TargetAccountURI) targetAccountURI, err := url.Parse(m.TargetAccountURI)
if err != nil { if err != nil {
log.Debugf("populateStatusMentions: error parsing mentioned account uri %s: %s", m.TargetAccountURI, err) log.Debugf(ctx, "error parsing mentioned account uri %s: %s", m.TargetAccountURI, err)
continue continue
} }
@ -342,7 +342,7 @@ func (d *deref) populateStatusMentions(ctx context.Context, status *gtsmodel.Sta
if a, err := d.db.GetAccountByURI(ctx, targetAccountURI.String()); err != nil { if a, err := d.db.GetAccountByURI(ctx, targetAccountURI.String()); err != nil {
errs = append(errs, err.Error()) errs = append(errs, err.Error())
} else { } else {
log.Debugf("populateStatusMentions: got target account %s with id %s through GetAccountByURI", targetAccountURI, a.ID) log.Debugf(ctx, "got target account %s with id %s through GetAccountByURI", targetAccountURI, a.ID)
targetAccount = a targetAccount = a
} }
@ -352,13 +352,13 @@ func (d *deref) populateStatusMentions(ctx context.Context, status *gtsmodel.Sta
if a, err := d.GetAccountByURI(ctx, requestingUsername, targetAccountURI, false); err != nil { if a, err := d.GetAccountByURI(ctx, requestingUsername, targetAccountURI, false); err != nil {
errs = append(errs, err.Error()) errs = append(errs, err.Error())
} else { } else {
log.Debugf("populateStatusMentions: got target account %s with id %s through GetRemoteAccount", targetAccountURI, a.ID) log.Debugf(ctx, "got target account %s with id %s through GetRemoteAccount", targetAccountURI, a.ID)
targetAccount = a targetAccount = a
} }
} }
if targetAccount == nil { if targetAccount == nil {
log.Debugf("populateStatusMentions: couldn't get target account %s: %s", m.TargetAccountURI, strings.Join(errs, " : ")) log.Debugf(ctx, "couldn't get target account %s: %s", m.TargetAccountURI, strings.Join(errs, " : "))
continue continue
} }
@ -419,13 +419,13 @@ func (d *deref) populateStatusAttachments(ctx context.Context, status *gtsmodel.
Blurhash: &a.Blurhash, Blurhash: &a.Blurhash,
}) })
if err != nil { if err != nil {
log.Errorf("populateStatusAttachments: couldn't get remote media %s: %s", a.RemoteURL, err) log.Errorf(ctx, "couldn't get remote media %s: %s", a.RemoteURL, err)
continue continue
} }
attachment, err := processingMedia.LoadAttachment(ctx) attachment, err := processingMedia.LoadAttachment(ctx)
if err != nil { if err != nil {
log.Errorf("populateStatusAttachments: couldn't load remote attachment %s: %s", a.RemoteURL, err) log.Errorf(ctx, "couldn't load remote attachment %s: %s", a.RemoteURL, err)
continue continue
} }

View file

@ -45,10 +45,11 @@
// //
// This does not return error, as for robustness we do not want to error-out on a status because another further up / down has issues. // This does not return error, as for robustness we do not want to error-out on a status because another further up / down has issues.
func (d *deref) DereferenceThread(ctx context.Context, username string, statusIRI *url.URL, status *gtsmodel.Status, statusable ap.Statusable) { func (d *deref) DereferenceThread(ctx context.Context, username string, statusIRI *url.URL, status *gtsmodel.Status, statusable ap.Statusable) {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"username", username}, WithFields(kv.Fields{
{"statusIRI", status.URI}, {"username", username},
}...) {"statusIRI", status.URI},
}...)
// Log function start // Log function start
l.Trace("beginning") l.Trace("beginning")
@ -72,10 +73,11 @@ func (d *deref) dereferenceStatusAncestors(ctx context.Context, username string,
ogIRI := status.URI ogIRI := status.URI
// Start log entry with fields // Start log entry with fields
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"username", username}, WithFields(kv.Fields{
{"statusIRI", ogIRI}, {"username", username},
}...) {"statusIRI", ogIRI},
}...)
// Log function start // Log function start
l.Trace("beginning") l.Trace("beginning")
@ -132,10 +134,11 @@ func (d *deref) dereferenceStatusDescendants(ctx context.Context, username strin
ogIRI := statusIRI ogIRI := statusIRI
// Start log entry with fields // Start log entry with fields
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"username", username}, WithFields(kv.Fields{
{"statusIRI", ogIRI}, {"username", username},
}...) {"statusIRI", ogIRI},
}...)
// Log function start // Log function start
l.Trace("beginning") l.Trace("beginning")

View file

@ -56,7 +56,7 @@ func newFederatingActor(c pub.CommonBehavior, s2s pub.FederatingProtocol, db pub
// method will guaranteed work for non-custom Actors. For custom actors, // method will guaranteed work for non-custom Actors. For custom actors,
// care should be used to not call this method if only C2S is supported. // care should be used to not call this method if only C2S is supported.
func (f *federatingActor) Send(c context.Context, outbox *url.URL, t vocab.Type) (pub.Activity, error) { func (f *federatingActor) Send(c context.Context, outbox *url.URL, t vocab.Type) (pub.Activity, error) {
log.Infof("federating actor: send activity %s via outbox %s", t.GetTypeName(), outbox) log.Infof(c, "send activity %s via outbox %s", t.GetTypeName(), outbox)
return f.actor.Send(c, outbox, t) return f.actor.Send(c, outbox, t)
} }

View file

@ -53,8 +53,9 @@ func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {
if err != nil { if err != nil {
return err return err
} }
l := log.WithField("create", i) l := log.WithContext(ctx).
l.Debug("entering Create") WithField("create", i)
l.Trace("entering Create")
} }
receivingAccount, requestingAccount := extractFromCtx(ctx) receivingAccount, requestingAccount := extractFromCtx(ctx)
@ -164,10 +165,11 @@ func (f *federatingDB) activityCreate(ctx context.Context, asType vocab.Type, re
// createNote handles a Create activity with a Note type. // createNote handles a Create activity with a Note type.
func (f *federatingDB) createNote(ctx context.Context, note vocab.ActivityStreamsNote, receivingAccount *gtsmodel.Account, requestingAccount *gtsmodel.Account) error { func (f *federatingDB) createNote(ctx context.Context, note vocab.ActivityStreamsNote, receivingAccount *gtsmodel.Account, requestingAccount *gtsmodel.Account) error {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"receivingAccount", receivingAccount.URI}, WithFields(kv.Fields{
{"requestingAccount", requestingAccount.URI}, {"receivingAccount", receivingAccount.URI},
}...) {"requestingAccount", requestingAccount.URI},
}...)
// Check if we have a forward. // Check if we have a forward.
// In other words, was the note posted to our inbox by at least one actor who actually created the note, or are they just forwarding it? // In other words, was the note posted to our inbox by at least one actor who actually created the note, or are they just forwarding it?

View file

@ -35,9 +35,10 @@
// //
// The library makes this call only after acquiring a lock first. // The library makes this call only after acquiring a lock first.
func (f *federatingDB) Delete(ctx context.Context, id *url.URL) error { func (f *federatingDB) Delete(ctx context.Context, id *url.URL) error {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"id", id}, WithFields(kv.Fields{
}...) {"id", id},
}...)
l.Debug("entering Delete") l.Debug("entering Delete")
receivingAccount, requestingAccount := extractFromCtx(ctx) receivingAccount, requestingAccount := extractFromCtx(ctx)

View file

@ -32,10 +32,11 @@
// The library makes this call only after acquiring a lock first. // The library makes this call only after acquiring a lock first.
// //
// Implementation note: this just straight up isn't implemented, and doesn't *really* need to be either. // Implementation note: this just straight up isn't implemented, and doesn't *really* need to be either.
func (f *federatingDB) Exists(c context.Context, id *url.URL) (exists bool, err error) { func (f *federatingDB) Exists(ctx context.Context, id *url.URL) (exists bool, err error) {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"id", id}, WithFields(kv.Fields{
}...) {"id", id},
}...)
l.Debug("entering Exists") l.Debug("entering Exists")
return false, nil return false, nil
} }

View file

@ -18,9 +18,10 @@
// //
// The library makes this call only after acquiring a lock first. // The library makes this call only after acquiring a lock first.
func (f *federatingDB) Followers(ctx context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) { func (f *federatingDB) Followers(ctx context.Context, actorIRI *url.URL) (followers vocab.ActivityStreamsCollection, err error) {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"id", actorIRI}, WithFields(kv.Fields{
}...) {"id", actorIRI},
}...)
l.Debug("entering Followers") l.Debug("entering Followers")
acct, err := f.getAccountForIRI(ctx, actorIRI) acct, err := f.getAccountForIRI(ctx, actorIRI)

View file

@ -36,9 +36,10 @@
// //
// The library makes this call only after acquiring a lock first. // The library makes this call only after acquiring a lock first.
func (f *federatingDB) Following(ctx context.Context, actorIRI *url.URL) (following vocab.ActivityStreamsCollection, err error) { func (f *federatingDB) Following(ctx context.Context, actorIRI *url.URL) (following vocab.ActivityStreamsCollection, err error) {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"id", actorIRI}, WithFields(kv.Fields{
}...) {"id", actorIRI},
}...)
l.Debug("entering Following") l.Debug("entering Following")
acct, err := f.getAccountForIRI(ctx, actorIRI) acct, err := f.getAccountForIRI(ctx, actorIRI)

View file

@ -33,7 +33,8 @@
// //
// The library makes this call only after acquiring a lock first. // The library makes this call only after acquiring a lock first.
func (f *federatingDB) Get(ctx context.Context, id *url.URL) (value vocab.Type, err error) { func (f *federatingDB) Get(ctx context.Context, id *url.URL) (value vocab.Type, err error) {
l := log.WithFields(kv.Fields{{"id", id}}...) l := log.WithContext(ctx).
WithFields(kv.Fields{{"id", id}}...)
l.Debug("entering Get") l.Debug("entering Get")
switch { switch {

View file

@ -35,9 +35,10 @@
// the database has an entry for the IRI. // the database has an entry for the IRI.
// The library makes this call only after acquiring a lock first. // The library makes this call only after acquiring a lock first.
func (f *federatingDB) Owns(ctx context.Context, id *url.URL) (bool, error) { func (f *federatingDB) Owns(ctx context.Context, id *url.URL) (bool, error) {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"id", id}, WithFields(kv.Fields{
}...) {"id", id},
}...)
l.Debug("entering Owns") l.Debug("entering Owns")
// if the id host isn't this instance host, we don't own this IRI // if the id host isn't this instance host, we don't own this IRI

View file

@ -304,7 +304,7 @@ func extractFromCtx(ctx context.Context) (receivingAccount, requestingAccount *g
var ok bool var ok bool
receivingAccount, ok = receivingAccountI.(*gtsmodel.Account) receivingAccount, ok = receivingAccountI.(*gtsmodel.Account)
if !ok { if !ok {
log.Panicf("extractFromCtx: context entry with key %s could not be asserted to *gtsmodel.Account", ap.ContextReceivingAccount) log.Panicf(ctx, "context entry with key %s could not be asserted to *gtsmodel.Account", ap.ContextReceivingAccount)
} }
} }
@ -313,7 +313,7 @@ func extractFromCtx(ctx context.Context) (receivingAccount, requestingAccount *g
var ok bool var ok bool
requestingAccount, ok = requestingAcctI.(*gtsmodel.Account) requestingAccount, ok = requestingAcctI.(*gtsmodel.Account)
if !ok { if !ok {
log.Panicf("extractFromCtx: context entry with key %s could not be asserted to *gtsmodel.Account", ap.ContextRequestingAccount) log.Panicf(ctx, "context entry with key %s could not be asserted to *gtsmodel.Account", ap.ContextRequestingAccount)
} }
} }

View file

@ -138,10 +138,11 @@ func (f *federator) PostInboxRequestBodyHook(ctx context.Context, r *http.Reques
// authenticated must be true and error nil. The request will continue // authenticated must be true and error nil. The request will continue
// to be processed. // to be processed.
func (f *federator) AuthenticatePostInbox(ctx context.Context, w http.ResponseWriter, r *http.Request) (context.Context, bool, error) { func (f *federator) AuthenticatePostInbox(ctx context.Context, w http.ResponseWriter, r *http.Request) (context.Context, bool, error) {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"useragent", r.UserAgent()}, WithFields(kv.Fields{
{"url", r.URL.String()}, {"useragent", r.UserAgent()},
}...) {"url", r.URL.String()},
}...)
l.Trace("received request to authenticate") l.Trace("received request to authenticate")
if !uris.IsInboxPath(r.URL) { if !uris.IsInboxPath(r.URL) {
@ -242,7 +243,7 @@ func (f *federator) AuthenticatePostInbox(ctx context.Context, w http.ResponseWr
// blocked must be false and error nil. The request will continue // blocked must be false and error nil. The request will continue
// to be processed. // to be processed.
func (f *federator) Blocked(ctx context.Context, actorIRIs []*url.URL) (bool, error) { func (f *federator) Blocked(ctx context.Context, actorIRIs []*url.URL) (bool, error) {
log.Debugf("entering BLOCKED function with IRI list: %+v", actorIRIs) log.Tracef(ctx, "entering BLOCKED function with IRI list: %+v", actorIRIs)
// check domain blocks first for the given actor IRIs // check domain blocks first for the given actor IRIs
blocked, err := f.db.AreURIsBlocked(ctx, actorIRIs) blocked, err := f.db.AreURIsBlocked(ctx, actorIRIs)
@ -257,7 +258,7 @@ func (f *federator) Blocked(ctx context.Context, actorIRIs []*url.URL) (bool, er
otherInvolvedIRIsI := ctx.Value(ap.ContextOtherInvolvedIRIs) otherInvolvedIRIsI := ctx.Value(ap.ContextOtherInvolvedIRIs)
otherInvolvedIRIs, ok := otherInvolvedIRIsI.([]*url.URL) otherInvolvedIRIs, ok := otherInvolvedIRIsI.([]*url.URL)
if !ok { if !ok {
log.Error("other involved IRIs not set on request context") log.Error(ctx, "other involved IRIs not set on request context")
return false, errors.New("other involved IRIs not set on request context, so couldn't determine blocks") return false, errors.New("other involved IRIs not set on request context, so couldn't determine blocks")
} }
blocked, err = f.db.AreURIsBlocked(ctx, otherInvolvedIRIs) blocked, err = f.db.AreURIsBlocked(ctx, otherInvolvedIRIs)
@ -272,13 +273,13 @@ func (f *federator) Blocked(ctx context.Context, actorIRIs []*url.URL) (bool, er
receivingAccountI := ctx.Value(ap.ContextReceivingAccount) receivingAccountI := ctx.Value(ap.ContextReceivingAccount)
receivingAccount, ok := receivingAccountI.(*gtsmodel.Account) receivingAccount, ok := receivingAccountI.(*gtsmodel.Account)
if !ok { if !ok {
log.Error("receiving account not set on request context") log.Error(ctx, "receiving account not set on request context")
return false, errors.New("receiving account not set on request context, so couldn't determine blocks") return false, errors.New("receiving account not set on request context, so couldn't determine blocks")
} }
requestingAccountI := ctx.Value(ap.ContextRequestingAccount) requestingAccountI := ctx.Value(ap.ContextRequestingAccount)
requestingAccount, ok := requestingAccountI.(*gtsmodel.Account) requestingAccount, ok := requestingAccountI.(*gtsmodel.Account)
if !ok { if !ok {
log.Error("requesting account not set on request context") log.Error(ctx, "requesting account not set on request context")
return false, errors.New("requesting account not set on request context, so couldn't determine blocks") return false, errors.New("requesting account not set on request context, so couldn't determine blocks")
} }
// the receiver shouldn't block the sender // the receiver shouldn't block the sender
@ -384,10 +385,11 @@ func(ctx context.Context, announce vocab.ActivityStreamsAnnounce) error {
// type and extension, so the unhandled ones are passed to // type and extension, so the unhandled ones are passed to
// DefaultCallback. // DefaultCallback.
func (f *federator) DefaultCallback(ctx context.Context, activity pub.Activity) error { func (f *federator) DefaultCallback(ctx context.Context, activity pub.Activity) error {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"aptype", activity.GetTypeName()}, WithFields(kv.Fields{
}...) {"aptype", activity.GetTypeName()},
l.Debugf("received unhandle-able activity type so ignoring it") }...)
l.Debug("received unhandle-able activity type so ignoring it")
return nil return nil
} }

View file

@ -180,12 +180,13 @@ func (c *Client) Do(req *http.Request) (*http.Response, error) {
if !ok { if !ok {
// No spot acquired, log warning // No spot acquired, log warning
log.WithFields(kv.Fields{ log.WithContext(req.Context()).
{K: "queue", V: len(wait)}, WithFields(kv.Fields{
{K: "method", V: req.Method}, {K: "queue", V: len(wait)},
{K: "host", V: req.Host}, {K: "method", V: req.Method},
{K: "uri", V: req.URL.RequestURI()}, {K: "host", V: req.Host},
}...).Warn("full request queue") {K: "uri", V: req.URL.RequestURI()},
}...).Warn("full request queue")
select { select {
case <-req.Context().Done(): case <-req.Context().Done():

View file

@ -19,6 +19,7 @@
package log package log
import ( import (
"context"
"fmt" "fmt"
"syscall" "syscall"
@ -27,91 +28,97 @@
) )
type Entry struct { type Entry struct {
fields []kv.Field ctx context.Context
kvs []kv.Field
} }
func (e Entry) WithField(key string, value interface{}) Entry { func (e Entry) WithContext(ctx context.Context) Entry {
e.fields = append(e.fields, kv.Field{K: key, V: value}) e.ctx = ctx
return e return e
} }
func (e Entry) WithFields(fields ...kv.Field) Entry { func (e Entry) WithField(key string, value interface{}) Entry {
e.fields = append(e.fields, fields...) e.kvs = append(e.kvs, kv.Field{K: key, V: value})
return e
}
func (e Entry) WithFields(kvs ...kv.Field) Entry {
e.kvs = append(e.kvs, kvs...)
return e return e
} }
func (e Entry) Trace(a ...interface{}) { func (e Entry) Trace(a ...interface{}) {
logf(3, level.TRACE, e.fields, args(len(a)), a...) logf(e.ctx, 3, level.TRACE, e.kvs, args(len(a)), a...)
} }
func (e Entry) Tracef(s string, a ...interface{}) { func (e Entry) Tracef(s string, a ...interface{}) {
logf(3, level.TRACE, e.fields, s, a...) logf(e.ctx, 3, level.TRACE, e.kvs, s, a...)
} }
func (e Entry) Debug(a ...interface{}) { func (e Entry) Debug(a ...interface{}) {
logf(3, level.DEBUG, e.fields, args(len(a)), a...) logf(e.ctx, 3, level.DEBUG, e.kvs, args(len(a)), a...)
} }
func (e Entry) Debugf(s string, a ...interface{}) { func (e Entry) Debugf(s string, a ...interface{}) {
logf(3, level.DEBUG, e.fields, s, a...) logf(e.ctx, 3, level.DEBUG, e.kvs, s, a...)
} }
func (e Entry) Info(a ...interface{}) { func (e Entry) Info(a ...interface{}) {
logf(3, level.INFO, e.fields, args(len(a)), a...) logf(e.ctx, 3, level.INFO, e.kvs, args(len(a)), a...)
} }
func (e Entry) Infof(s string, a ...interface{}) { func (e Entry) Infof(s string, a ...interface{}) {
logf(3, level.INFO, e.fields, s, a...) logf(e.ctx, 3, level.INFO, e.kvs, s, a...)
} }
func (e Entry) Warn(a ...interface{}) { func (e Entry) Warn(a ...interface{}) {
logf(3, level.WARN, e.fields, args(len(a)), a...) logf(e.ctx, 3, level.WARN, e.kvs, args(len(a)), a...)
} }
func (e Entry) Warnf(s string, a ...interface{}) { func (e Entry) Warnf(s string, a ...interface{}) {
logf(3, level.WARN, e.fields, s, a...) logf(e.ctx, 3, level.WARN, e.kvs, s, a...)
} }
func (e Entry) Error(a ...interface{}) { func (e Entry) Error(a ...interface{}) {
logf(3, level.ERROR, e.fields, args(len(a)), a...) logf(e.ctx, 3, level.ERROR, e.kvs, args(len(a)), a...)
} }
func (e Entry) Errorf(s string, a ...interface{}) { func (e Entry) Errorf(s string, a ...interface{}) {
logf(3, level.ERROR, e.fields, s, a...) logf(e.ctx, 3, level.ERROR, e.kvs, s, a...)
} }
func (e Entry) Fatal(a ...interface{}) { func (e Entry) Fatal(a ...interface{}) {
defer syscall.Exit(1) defer syscall.Exit(1)
logf(3, level.FATAL, e.fields, args(len(a)), a...) logf(e.ctx, 3, level.FATAL, e.kvs, args(len(a)), a...)
} }
func (e Entry) Fatalf(s string, a ...interface{}) { func (e Entry) Fatalf(s string, a ...interface{}) {
defer syscall.Exit(1) defer syscall.Exit(1)
logf(3, level.FATAL, e.fields, s, a...) logf(e.ctx, 3, level.FATAL, e.kvs, s, a...)
} }
func (e Entry) Panic(a ...interface{}) { func (e Entry) Panic(a ...interface{}) {
defer panic(fmt.Sprint(a...)) defer panic(fmt.Sprint(a...))
logf(3, level.PANIC, e.fields, args(len(a)), a...) logf(e.ctx, 3, level.PANIC, e.kvs, args(len(a)), a...)
} }
func (e Entry) Panicf(s string, a ...interface{}) { func (e Entry) Panicf(s string, a ...interface{}) {
defer panic(fmt.Sprintf(s, a...)) defer panic(fmt.Sprintf(s, a...))
logf(3, level.PANIC, e.fields, s, a...) logf(e.ctx, 3, level.PANIC, e.kvs, s, a...)
} }
func (e Entry) Log(lvl level.LEVEL, a ...interface{}) { func (e Entry) Log(lvl level.LEVEL, a ...interface{}) {
logf(3, lvl, e.fields, args(len(a)), a...) logf(e.ctx, 3, lvl, e.kvs, args(len(a)), a...)
} }
func (e Entry) Logf(lvl level.LEVEL, s string, a ...interface{}) { func (e Entry) Logf(lvl level.LEVEL, s string, a ...interface{}) {
logf(3, lvl, e.fields, s, a...) logf(e.ctx, 3, lvl, e.kvs, s, a...)
} }
func (e Entry) Print(a ...interface{}) { func (e Entry) Print(a ...interface{}) {
printf(3, e.fields, args(len(a)), a...) printf(3, e.kvs, args(len(a)), a...)
} }
func (e Entry) Printf(s string, a ...interface{}) { func (e Entry) Printf(s string, a ...interface{}) {
printf(3, e.fields, s, a...) printf(3, e.kvs, s, a...)
} }

View file

@ -19,6 +19,7 @@
package log package log
import ( import (
"context"
"fmt" "fmt"
"log/syslog" "log/syslog"
"os" "os"
@ -38,13 +39,21 @@
// lvlstrs is the lookup table of log levels to strings. // lvlstrs is the lookup table of log levels to strings.
lvlstrs = level.Default() lvlstrs = level.Default()
// Syslog output, only set if enabled. // syslog output, only set if enabled.
sysout *syslog.Writer sysout *syslog.Writer
// timefmt is the logging time format used. // timefmt is the logging time format used.
timefmt = "02/01/2006 15:04:05.000" timefmt = "02/01/2006 15:04:05.000"
// ctxhooks allows modifying log content based on context.
ctxhooks []func(context.Context, []kv.Field) []kv.Field
) )
// Hook adds the given hook to the global logger context hooks stack.
func Hook(hook func(ctx context.Context, kvs []kv.Field) []kv.Field) {
ctxhooks = append(ctxhooks, hook)
}
// Level returns the currently set log level. // Level returns the currently set log level.
func Level() level.LEVEL { func Level() level.LEVEL {
return level.LEVEL(loglvl.Load()) return level.LEVEL(loglvl.Load())
@ -60,82 +69,86 @@ func New() Entry {
return Entry{} return Entry{}
} }
func WithContext(ctx context.Context) Entry {
return Entry{ctx: ctx}
}
func WithField(key string, value interface{}) Entry { func WithField(key string, value interface{}) Entry {
return Entry{fields: []kv.Field{{K: key, V: value}}} return New().WithField(key, value)
} }
func WithFields(fields ...kv.Field) Entry { func WithFields(fields ...kv.Field) Entry {
return Entry{fields: fields} return New().WithFields(fields...)
} }
func Trace(a ...interface{}) { func Trace(ctx context.Context, a ...interface{}) {
logf(3, level.TRACE, nil, args(len(a)), a...) logf(ctx, 3, level.TRACE, nil, args(len(a)), a...)
} }
func Tracef(s string, a ...interface{}) { func Tracef(ctx context.Context, s string, a ...interface{}) {
logf(3, level.TRACE, nil, s, a...) logf(ctx, 3, level.TRACE, nil, s, a...)
} }
func Debug(a ...interface{}) { func Debug(ctx context.Context, a ...interface{}) {
logf(3, level.DEBUG, nil, args(len(a)), a...) logf(ctx, 3, level.DEBUG, nil, args(len(a)), a...)
} }
func Debugf(s string, a ...interface{}) { func Debugf(ctx context.Context, s string, a ...interface{}) {
logf(3, level.DEBUG, nil, s, a...) logf(ctx, 3, level.DEBUG, nil, s, a...)
} }
func Info(a ...interface{}) { func Info(ctx context.Context, a ...interface{}) {
logf(3, level.INFO, nil, args(len(a)), a...) logf(ctx, 3, level.INFO, nil, args(len(a)), a...)
} }
func Infof(s string, a ...interface{}) { func Infof(ctx context.Context, s string, a ...interface{}) {
logf(3, level.INFO, nil, s, a...) logf(ctx, 3, level.INFO, nil, s, a...)
} }
func Warn(a ...interface{}) { func Warn(ctx context.Context, a ...interface{}) {
logf(3, level.WARN, nil, args(len(a)), a...) logf(ctx, 3, level.WARN, nil, args(len(a)), a...)
} }
func Warnf(s string, a ...interface{}) { func Warnf(ctx context.Context, s string, a ...interface{}) {
logf(3, level.WARN, nil, s, a...) logf(ctx, 3, level.WARN, nil, s, a...)
} }
func Error(a ...interface{}) { func Error(ctx context.Context, a ...interface{}) {
logf(3, level.ERROR, nil, args(len(a)), a...) logf(ctx, 3, level.ERROR, nil, args(len(a)), a...)
} }
func Errorf(s string, a ...interface{}) { func Errorf(ctx context.Context, s string, a ...interface{}) {
logf(3, level.ERROR, nil, s, a...) logf(ctx, 3, level.ERROR, nil, s, a...)
} }
func Fatal(a ...interface{}) { func Fatal(ctx context.Context, a ...interface{}) {
defer syscall.Exit(1) defer syscall.Exit(1)
logf(3, level.FATAL, nil, args(len(a)), a...) logf(ctx, 3, level.FATAL, nil, args(len(a)), a...)
} }
func Fatalf(s string, a ...interface{}) { func Fatalf(ctx context.Context, s string, a ...interface{}) {
defer syscall.Exit(1) defer syscall.Exit(1)
logf(3, level.FATAL, nil, s, a...) logf(ctx, 3, level.FATAL, nil, s, a...)
} }
func Panic(a ...interface{}) { func Panic(ctx context.Context, a ...interface{}) {
defer panic(fmt.Sprint(a...)) defer panic(fmt.Sprint(a...))
logf(3, level.PANIC, nil, args(len(a)), a...) logf(ctx, 3, level.PANIC, nil, args(len(a)), a...)
} }
func Panicf(s string, a ...interface{}) { func Panicf(ctx context.Context, s string, a ...interface{}) {
defer panic(fmt.Sprintf(s, a...)) defer panic(fmt.Sprintf(s, a...))
logf(3, level.PANIC, nil, s, a...) logf(ctx, 3, level.PANIC, nil, s, a...)
} }
// Log will log formatted args as 'msg' field to the log at given level. // Log will log formatted args as 'msg' field to the log at given level.
func Log(lvl level.LEVEL, a ...interface{}) { func Log(ctx context.Context, lvl level.LEVEL, a ...interface{}) {
logf(3, lvl, nil, args(len(a)), a...) logf(ctx, 3, lvl, nil, args(len(a)), a...)
} }
// Logf will log format string as 'msg' field to the log at given level. // Logf will log format string as 'msg' field to the log at given level.
func Logf(lvl level.LEVEL, s string, a ...interface{}) { func Logf(ctx context.Context, lvl level.LEVEL, s string, a ...interface{}) {
logf(3, lvl, nil, s, a...) logf(ctx, 3, lvl, nil, s, a...)
} }
// Print will log formatted args to the stdout log output. // Print will log formatted args to the stdout log output.
@ -186,7 +199,7 @@ func printf(depth int, fields []kv.Field, s string, a ...interface{}) {
putBuf(buf) putBuf(buf)
} }
func logf(depth int, lvl level.LEVEL, fields []kv.Field, s string, a ...interface{}) { func logf(ctx context.Context, depth int, lvl level.LEVEL, fields []kv.Field, s string, a ...interface{}) {
var out *os.File var out *os.File
// Check if enabled. // Check if enabled.
@ -220,6 +233,13 @@ func logf(depth int, lvl level.LEVEL, fields []kv.Field, s string, a ...interfac
buf.B = append(buf.B, lvlstrs[lvl]...) buf.B = append(buf.B, lvlstrs[lvl]...)
buf.B = append(buf.B, ' ') buf.B = append(buf.B, ' ')
if ctx != nil {
// Pass context through hooks.
for _, hook := range ctxhooks {
fields = hook(ctx, fields)
}
}
// Append formatted fields with msg // Append formatted fields with msg
kv.Fields(append(fields, kv.Field{ kv.Fields(append(fields, kv.Field{
K: "msg", V: fmt.Sprintf(s, a...), K: "msg", V: fmt.Sprintf(s, a...),

View file

@ -66,14 +66,14 @@ func (suite *SyslogTestSuite) TearDownTest() {
} }
func (suite *SyslogTestSuite) TestSyslog() { func (suite *SyslogTestSuite) TestSyslog() {
log.Info("this is a test of the emergency broadcast system!") log.Info(nil, "this is a test of the emergency broadcast system!")
entry := <-suite.syslogChannel entry := <-suite.syslogChannel
suite.Regexp(regexp.MustCompile(`timestamp=.* func=.* level=INFO msg="this is a test of the emergency broadcast system!"`), entry["content"]) suite.Regexp(regexp.MustCompile(`timestamp=.* func=.* level=INFO msg="this is a test of the emergency broadcast system!"`), entry["content"])
} }
func (suite *SyslogTestSuite) TestSyslogLongMessage() { func (suite *SyslogTestSuite) TestSyslogLongMessage() {
log.Warn(longMessage) log.Warn(nil, longMessage)
funcName := log.Caller(2) funcName := log.Caller(2)
prefix := fmt.Sprintf(`timestamp="02/01/2006 15:04:05.000" func=%s level=WARN msg="`, funcName) prefix := fmt.Sprintf(`timestamp="02/01/2006 15:04:05.000" func=%s level=WARN msg="`, funcName)
@ -104,7 +104,7 @@ func (suite *SyslogTestSuite) TestSyslogLongMessageUnixgram() {
testrig.InitTestLog() testrig.InitTestLog()
log.Warn(longMessage) log.Warn(nil, longMessage)
funcName := log.Caller(2) funcName := log.Caller(2)
prefix := fmt.Sprintf(`timestamp="02/01/2006 15:04:05.000" func=%s level=WARN msg="`, funcName) prefix := fmt.Sprintf(`timestamp="02/01/2006 15:04:05.000" func=%s level=WARN msg="`, funcName)

View file

@ -454,8 +454,8 @@ func scheduleCleanupJobs(m *manager) {
m.state.Workers.Scheduler.Schedule(sched.NewJob(func(now time.Time) { m.state.Workers.Scheduler.Schedule(sched.NewJob(func(now time.Time) {
err := m.PruneAll(doneCtx, config.GetMediaRemoteCacheDays(), true) err := m.PruneAll(doneCtx, config.GetMediaRemoteCacheDays(), true)
if err != nil { if err != nil {
log.Errorf("error during prune: %v", err) log.Errorf(nil, "error during prune: %v", err)
} }
log.Infof("finished pruning all in %s", time.Since(now)) log.Infof(nil, "finished pruning all in %s", time.Since(now))
}).EveryAt(midnight, day)) }).EveryAt(midnight, day))
} }

View file

@ -67,7 +67,7 @@ func (p *ProcessingEmoji) LoadEmoji(ctx context.Context) (*gtsmodel.Emoji, error
if !done { if !done {
// Provided context was cancelled, e.g. request cancelled // Provided context was cancelled, e.g. request cancelled
// early. Queue this item for asynchronous processing. // early. Queue this item for asynchronous processing.
log.Warnf("reprocessing emoji %s after canceled ctx", p.emoji.ID) log.Warnf(ctx, "reprocessing emoji %s after canceled ctx", p.emoji.ID)
go p.mgr.state.Workers.Media.Enqueue(p.Process) go p.mgr.state.Workers.Media.Enqueue(p.Process)
} }
@ -77,7 +77,7 @@ func (p *ProcessingEmoji) LoadEmoji(ctx context.Context) (*gtsmodel.Emoji, error
// Process allows the receiving object to fit the runners.WorkerFunc signature. It performs a (blocking) load and logs on error. // Process allows the receiving object to fit the runners.WorkerFunc signature. It performs a (blocking) load and logs on error.
func (p *ProcessingEmoji) Process(ctx context.Context) { func (p *ProcessingEmoji) Process(ctx context.Context) {
if _, _, err := p.load(ctx); err != nil { if _, _, err := p.load(ctx); err != nil {
log.Errorf("error processing emoji: %v", err) log.Errorf(ctx, "error processing emoji: %v", err)
} }
} }
@ -167,7 +167,7 @@ func (p *ProcessingEmoji) store(ctx context.Context) error {
// Ensure post callback gets called. // Ensure post callback gets called.
if err := p.postFn(ctx); err != nil { if err := p.postFn(ctx); err != nil {
log.Errorf("error executing postdata function: %v", err) log.Errorf(ctx, "error executing postdata function: %v", err)
} }
}() }()
@ -180,7 +180,7 @@ func (p *ProcessingEmoji) store(ctx context.Context) error {
defer func() { defer func() {
// Ensure data reader gets closed on return. // Ensure data reader gets closed on return.
if err := rc.Close(); err != nil { if err := rc.Close(); err != nil {
log.Errorf("error closing data reader: %v", err) log.Errorf(ctx, "error closing data reader: %v", err)
} }
}() }()
@ -251,7 +251,7 @@ func (p *ProcessingEmoji) store(ctx context.Context) error {
// This shouldn't already exist, but we do a check as it's worth logging. // This shouldn't already exist, but we do a check as it's worth logging.
if have, _ := p.mgr.state.Storage.Has(ctx, p.emoji.ImagePath); have { if have, _ := p.mgr.state.Storage.Has(ctx, p.emoji.ImagePath); have {
log.Warnf("emoji already exists at storage path: %s", p.emoji.ImagePath) log.Warnf(ctx, "emoji already exists at storage path: %s", p.emoji.ImagePath)
// Attempt to remove existing emoji at storage path (might be broken / out-of-date) // Attempt to remove existing emoji at storage path (might be broken / out-of-date)
if err := p.mgr.state.Storage.Delete(ctx, p.emoji.ImagePath); err != nil { if err := p.mgr.state.Storage.Delete(ctx, p.emoji.ImagePath); err != nil {
@ -267,8 +267,9 @@ func (p *ProcessingEmoji) store(ctx context.Context) error {
// Once again check size in case none was provided previously. // Once again check size in case none was provided previously.
if size := bytesize.Size(sz); size > maxSize { if size := bytesize.Size(sz); size > maxSize {
if err := p.mgr.state.Storage.Delete(ctx, p.emoji.ImagePath); err != nil { if err := p.mgr.state.Storage.Delete(ctx, p.emoji.ImagePath); err != nil {
log.Errorf("error removing too-large-emoji from storage: %v", err) log.Errorf(ctx, "error removing too-large-emoji from storage: %v", err)
} }
return fmt.Errorf("calculated emoji size %s greater than max allowed %s", size, maxSize) return fmt.Errorf("calculated emoji size %s greater than max allowed %s", size, maxSize)
} }
@ -308,8 +309,7 @@ func (p *ProcessingEmoji) finish(ctx context.Context) error {
// This shouldn't already exist, but we do a check as it's worth logging. // This shouldn't already exist, but we do a check as it's worth logging.
if have, _ := p.mgr.state.Storage.Has(ctx, p.emoji.ImageStaticPath); have { if have, _ := p.mgr.state.Storage.Has(ctx, p.emoji.ImageStaticPath); have {
log.Warnf("static emoji already exists at storage path: %s", p.emoji.ImagePath) log.Warnf(ctx, "static emoji already exists at storage path: %s", p.emoji.ImagePath)
// Attempt to remove static existing emoji at storage path (might be broken / out-of-date) // Attempt to remove static existing emoji at storage path (might be broken / out-of-date)
if err := p.mgr.state.Storage.Delete(ctx, p.emoji.ImageStaticPath); err != nil { if err := p.mgr.state.Storage.Delete(ctx, p.emoji.ImageStaticPath); err != nil {
return fmt.Errorf("error removing static emoji from storage: %v", err) return fmt.Errorf("error removing static emoji from storage: %v", err)

View file

@ -67,7 +67,7 @@ func (p *ProcessingMedia) LoadAttachment(ctx context.Context) (*gtsmodel.MediaAt
if !done { if !done {
// Provided context was cancelled, e.g. request cancelled // Provided context was cancelled, e.g. request cancelled
// early. Queue this item for asynchronous processing. // early. Queue this item for asynchronous processing.
log.Warnf("reprocessing media %s after canceled ctx", p.media.ID) log.Warnf(ctx, "reprocessing media %s after canceled ctx", p.media.ID)
go p.mgr.state.Workers.Media.Enqueue(p.Process) go p.mgr.state.Workers.Media.Enqueue(p.Process)
} }
@ -77,7 +77,7 @@ func (p *ProcessingMedia) LoadAttachment(ctx context.Context) (*gtsmodel.MediaAt
// Process allows the receiving object to fit the runners.WorkerFunc signature. It performs a (blocking) load and logs on error. // Process allows the receiving object to fit the runners.WorkerFunc signature. It performs a (blocking) load and logs on error.
func (p *ProcessingMedia) Process(ctx context.Context) { func (p *ProcessingMedia) Process(ctx context.Context) {
if _, _, err := p.load(ctx); err != nil { if _, _, err := p.load(ctx); err != nil {
log.Errorf("error processing media: %v", err) log.Errorf(ctx, "error processing media: %v", err)
} }
} }
@ -151,7 +151,7 @@ func (p *ProcessingMedia) store(ctx context.Context) error {
// ensure post callback gets called. // ensure post callback gets called.
if err := p.postFn(ctx); err != nil { if err := p.postFn(ctx); err != nil {
log.Errorf("error executing postdata function: %v", err) log.Errorf(ctx, "error executing postdata function: %v", err)
} }
}() }()
@ -164,7 +164,7 @@ func (p *ProcessingMedia) store(ctx context.Context) error {
defer func() { defer func() {
// Ensure data reader gets closed on return. // Ensure data reader gets closed on return.
if err := rc.Close(); err != nil { if err := rc.Close(); err != nil {
log.Errorf("error closing data reader: %v", err) log.Errorf(ctx, "error closing data reader: %v", err)
} }
}() }()
@ -220,7 +220,7 @@ func (p *ProcessingMedia) store(ctx context.Context) error {
// This shouldn't already exist, but we do a check as it's worth logging. // This shouldn't already exist, but we do a check as it's worth logging.
if have, _ := p.mgr.state.Storage.Has(ctx, p.media.File.Path); have { if have, _ := p.mgr.state.Storage.Has(ctx, p.media.File.Path); have {
log.Warnf("media already exists at storage path: %s", p.media.File.Path) log.Warnf(ctx, "media already exists at storage path: %s", p.media.File.Path)
// Attempt to remove existing media at storage path (might be broken / out-of-date) // Attempt to remove existing media at storage path (might be broken / out-of-date)
if err := p.mgr.state.Storage.Delete(ctx, p.media.File.Path); err != nil { if err := p.mgr.state.Storage.Delete(ctx, p.media.File.Path); err != nil {
@ -333,7 +333,7 @@ func (p *ProcessingMedia) finish(ctx context.Context) error {
// This shouldn't already exist, but we do a check as it's worth logging. // This shouldn't already exist, but we do a check as it's worth logging.
if have, _ := p.mgr.state.Storage.Has(ctx, p.media.Thumbnail.Path); have { if have, _ := p.mgr.state.Storage.Has(ctx, p.media.Thumbnail.Path); have {
log.Warnf("thumbnail already exists at storage path: %s", p.media.Thumbnail.Path) log.Warnf(ctx, "thumbnail already exists at storage path: %s", p.media.Thumbnail.Path)
// Attempt to remove existing thumbnail at storage path (might be broken / out-of-date) // Attempt to remove existing thumbnail at storage path (might be broken / out-of-date)
if err := p.mgr.state.Storage.Delete(ctx, p.media.Thumbnail.Path); err != nil { if err := p.mgr.state.Storage.Delete(ctx, p.media.Thumbnail.Path); err != nil {

View file

@ -48,34 +48,34 @@ func (m *manager) PruneAll(ctx context.Context, mediaCacheRemoteDays int, blocki
if err != nil { if err != nil {
errs = append(errs, fmt.Sprintf("error pruning unused local media (%s)", err)) errs = append(errs, fmt.Sprintf("error pruning unused local media (%s)", err))
} else { } else {
log.Infof("pruned %d unused local media", pruned) log.Infof(ctx, "pruned %d unused local media", pruned)
} }
pruned, err = m.PruneUnusedRemote(innerCtx, dry) pruned, err = m.PruneUnusedRemote(innerCtx, dry)
if err != nil { if err != nil {
errs = append(errs, fmt.Sprintf("error pruning unused remote media: (%s)", err)) errs = append(errs, fmt.Sprintf("error pruning unused remote media: (%s)", err))
} else { } else {
log.Infof("pruned %d unused remote media", pruned) log.Infof(ctx, "pruned %d unused remote media", pruned)
} }
pruned, err = m.UncacheRemote(innerCtx, mediaCacheRemoteDays, dry) pruned, err = m.UncacheRemote(innerCtx, mediaCacheRemoteDays, dry)
if err != nil { if err != nil {
errs = append(errs, fmt.Sprintf("error uncacheing remote media older than %d day(s): (%s)", mediaCacheRemoteDays, err)) errs = append(errs, fmt.Sprintf("error uncacheing remote media older than %d day(s): (%s)", mediaCacheRemoteDays, err))
} else { } else {
log.Infof("uncached %d remote media older than %d day(s)", pruned, mediaCacheRemoteDays) log.Infof(ctx, "uncached %d remote media older than %d day(s)", pruned, mediaCacheRemoteDays)
} }
pruned, err = m.PruneOrphaned(innerCtx, dry) pruned, err = m.PruneOrphaned(innerCtx, dry)
if err != nil { if err != nil {
errs = append(errs, fmt.Sprintf("error pruning orphaned media: (%s)", err)) errs = append(errs, fmt.Sprintf("error pruning orphaned media: (%s)", err))
} else { } else {
log.Infof("pruned %d orphaned media", pruned) log.Infof(ctx, "pruned %d orphaned media", pruned)
} }
if err := m.state.Storage.Storage.Clean(innerCtx); err != nil { if err := m.state.Storage.Storage.Clean(innerCtx); err != nil {
errs = append(errs, fmt.Sprintf("error cleaning storage: (%s)", err)) errs = append(errs, fmt.Sprintf("error cleaning storage: (%s)", err))
} else { } else {
log.Info("cleaned storage") log.Info(ctx, "cleaned storage")
} }
return errs.Combine() return errs.Combine()
@ -87,7 +87,7 @@ func (m *manager) PruneAll(ctx context.Context, mediaCacheRemoteDays int, blocki
go func() { go func() {
if err := f(context.Background()); err != nil { if err := f(context.Background()); err != nil {
log.Error(err) log.Error(ctx, err)
} }
}() }()

View file

@ -51,7 +51,7 @@ func (m *manager) RefetchEmojis(ctx context.Context, domain string, dereferenceM
if err != nil { if err != nil {
if !errors.Is(err, db.ErrNoEntries) { if !errors.Is(err, db.ErrNoEntries) {
// an actual error has occurred // an actual error has occurred
log.Errorf("error fetching emojis from database: %s", err) log.Errorf(ctx, "error fetching emojis from database: %s", err)
} }
break break
} }
@ -79,10 +79,10 @@ func (m *manager) RefetchEmojis(ctx context.Context, domain string, dereferenceM
// bail early if we've got nothing to do // bail early if we've got nothing to do
toRefetchCount := len(refetchIDs) toRefetchCount := len(refetchIDs)
if toRefetchCount == 0 { if toRefetchCount == 0 {
log.Debug("no remote emojis require a refetch") log.Debug(ctx, "no remote emojis require a refetch")
return 0, nil return 0, nil
} }
log.Debugf("%d remote emoji(s) require a refetch, doing that now...", toRefetchCount) log.Debugf(ctx, "%d remote emoji(s) require a refetch, doing that now...", toRefetchCount)
var totalRefetched int var totalRefetched int
for _, emojiID := range refetchIDs { for _, emojiID := range refetchIDs {
@ -94,13 +94,13 @@ func (m *manager) RefetchEmojis(ctx context.Context, domain string, dereferenceM
shortcodeDomain := util.ShortcodeDomain(emoji) shortcodeDomain := util.ShortcodeDomain(emoji)
if emoji.ImageRemoteURL == "" { if emoji.ImageRemoteURL == "" {
log.Errorf("remote emoji %s could not be refreshed because it has no ImageRemoteURL set", shortcodeDomain) log.Errorf(ctx, "remote emoji %s could not be refreshed because it has no ImageRemoteURL set", shortcodeDomain)
continue continue
} }
emojiImageIRI, err := url.Parse(emoji.ImageRemoteURL) emojiImageIRI, err := url.Parse(emoji.ImageRemoteURL)
if err != nil { if err != nil {
log.Errorf("remote emoji %s could not be refreshed because its ImageRemoteURL (%s) is not a valid uri: %s", shortcodeDomain, emoji.ImageRemoteURL, err) log.Errorf(ctx, "remote emoji %s could not be refreshed because its ImageRemoteURL (%s) is not a valid uri: %s", shortcodeDomain, emoji.ImageRemoteURL, err)
continue continue
} }
@ -116,16 +116,16 @@ func (m *manager) RefetchEmojis(ctx context.Context, domain string, dereferenceM
VisibleInPicker: emoji.VisibleInPicker, VisibleInPicker: emoji.VisibleInPicker,
}, true) }, true)
if err != nil { if err != nil {
log.Errorf("emoji %s could not be refreshed because of an error during processing: %s", shortcodeDomain, err) log.Errorf(ctx, "emoji %s could not be refreshed because of an error during processing: %s", shortcodeDomain, err)
continue continue
} }
if _, err := processingEmoji.LoadEmoji(ctx); err != nil { if _, err := processingEmoji.LoadEmoji(ctx); err != nil {
log.Errorf("emoji %s could not be refreshed because of an error during loading: %s", shortcodeDomain, err) log.Errorf(ctx, "emoji %s could not be refreshed because of an error during loading: %s", shortcodeDomain, err)
continue continue
} }
log.Tracef("refetched emoji %s successfully from remote", shortcodeDomain) log.Tracef(ctx, "refetched emoji %s successfully from remote", shortcodeDomain)
totalRefetched++ totalRefetched++
} }

View file

@ -44,7 +44,7 @@ func decodeVideoFrame(r io.Reader) (*gtsVideo, error) {
} }
defer func() { defer func() {
if err := tfs.Close(); err != nil { if err := tfs.Close(); err != nil {
log.Errorf("error closing temp file seeker: %s", err) log.Errorf(nil, "error closing temp file seeker: %s", err)
} }
}() }()

View file

@ -0,0 +1,111 @@
/*
GoToSocial
Copyright (C) 2021-2023 GoToSocial Authors admin@gotosocial.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package middleware
import (
"bufio"
"context"
"crypto/rand"
"encoding/base32"
"encoding/binary"
"io"
"sync"
"time"
"codeberg.org/gruf/go-kv"
"github.com/gin-gonic/gin"
"github.com/superseriousbusiness/gotosocial/internal/log"
)
type ctxType string
var (
// ridCtxKey is the key underwhich we store request IDs in a context.
ridCtxKey ctxType = "id"
// crand provides buffered reads of random input.
crand = bufio.NewReader(rand.Reader)
mrand sync.Mutex
// base32enc is a base 32 encoding based on a human-readable character set (no padding).
base32enc = base32.NewEncoding("0123456789abcdefghjkmnpqrstvwxyz").WithPadding(-1)
)
// generateID generates a new ID string.
func generateID() string {
// 0:8 = timestamp
// 8:12 = entropy
//
// inspired by ULID.
b := make([]byte, 12)
// Get current time in milliseconds.
ms := uint64(time.Now().UnixMilli())
// Store binary time data in byte buffer.
binary.LittleEndian.PutUint64(b[0:8], ms)
mrand.Lock()
// Read random bits into buffer end.
_, _ = io.ReadFull(crand, b[8:12])
mrand.Unlock()
// Encode the binary time+entropy ID.
return base32enc.EncodeToString(b)
}
// RequestID fetches the stored request ID from context.
func RequestID(ctx context.Context) string {
id, _ := ctx.Value(ridCtxKey).(string)
return id
}
// AddRequestID returns a gin middleware which adds a unique ID to each request (both response header and context).
func AddRequestID(header string) gin.HandlerFunc {
log.Hook(func(ctx context.Context, kvs []kv.Field) []kv.Field {
if id, _ := ctx.Value(ridCtxKey).(string); id != "" {
// Add stored request ID to log entry fields.
return append(kvs, kv.Field{K: "requestID", V: id})
}
return kvs
})
return func(c *gin.Context) {
// Look for existing ID.
id := c.GetHeader(header)
if id == "" {
// Generate new ID.
//
// 0:8 = timestamp
// 8:12 = entropy
id = generateID()
// Set the request ID in the req header in case we pass the request along
// to another service
c.Request.Header.Set(header, id)
}
// Store request ID in new request ctx and set new gin request obj.
ctx := context.WithValue(c.Request.Context(), ridCtxKey, id)
c.Request = c.Request.WithContext(ctx)
// Set the request ID in the rsp header.
c.Writer.Header().Set(header, id)
}
}

View file

@ -41,7 +41,7 @@ func SessionOptions() sessions.Options {
case "strict": case "strict":
samesite = http.SameSiteStrictMode samesite = http.SameSiteStrictMode
default: default:
log.Warnf("%s set to %s which is not recognized, defaulting to 'lax'", config.AdvancedCookiesSamesiteFlag(), config.GetAdvancedCookiesSamesite()) log.Warnf(nil, "%s set to %s which is not recognized, defaulting to 'lax'", config.AdvancedCookiesSamesiteFlag(), config.GetAdvancedCookiesSamesite())
samesite = http.SameSiteLaxMode samesite = http.SameSiteLaxMode
} }

View file

@ -36,13 +36,16 @@
// In case of an error, the request will be aborted with http code 500 internal server error. // In case of an error, the request will be aborted with http code 500 internal server error.
func SignatureCheck(isURIBlocked func(context.Context, *url.URL) (bool, db.Error)) func(*gin.Context) { func SignatureCheck(isURIBlocked func(context.Context, *url.URL) (bool, db.Error)) func(*gin.Context) {
return func(c *gin.Context) { return func(c *gin.Context) {
// Acquire ctx from gin request.
ctx := c.Request.Context()
// create the verifier from the request, this will error if the request wasn't signed // create the verifier from the request, this will error if the request wasn't signed
verifier, err := httpsig.NewVerifier(c.Request) verifier, err := httpsig.NewVerifier(c.Request)
if err != nil { if err != nil {
// Something went wrong, so we need to return regardless, but only actually // Something went wrong, so we need to return regardless, but only actually
// *abort* the request with 401 if a signature was present but malformed // *abort* the request with 401 if a signature was present but malformed
if err.Error() != noSignatureError { if err.Error() != noSignatureError {
log.Debugf("http signature was present but invalid: %s", err) log.Debugf(ctx, "http signature was present but invalid: %s", err)
c.AbortWithStatus(http.StatusUnauthorized) c.AbortWithStatus(http.StatusUnauthorized)
} }
return return
@ -54,13 +57,13 @@ func SignatureCheck(isURIBlocked func(context.Context, *url.URL) (bool, db.Error
requestingPublicKeyIDString := verifier.KeyId() requestingPublicKeyIDString := verifier.KeyId()
requestingPublicKeyID, err := url.Parse(requestingPublicKeyIDString) requestingPublicKeyID, err := url.Parse(requestingPublicKeyIDString)
if err != nil { if err != nil {
log.Debugf("http signature requesting public key id %s could not be parsed as a url: %s", requestingPublicKeyIDString, err) log.Debugf(ctx, "http signature requesting public key id %s could not be parsed as a url: %s", requestingPublicKeyIDString, err)
c.AbortWithStatus(http.StatusUnauthorized) c.AbortWithStatus(http.StatusUnauthorized)
return return
} else if requestingPublicKeyID == nil { } else if requestingPublicKeyID == nil {
// Key can sometimes be nil, according to url parse function: // Key can sometimes be nil, according to url parse function:
// 'Trying to parse a hostname and path without a scheme is invalid but may not necessarily return an error, due to parsing ambiguities' // 'Trying to parse a hostname and path without a scheme is invalid but may not necessarily return an error, due to parsing ambiguities'
log.Debugf("http signature requesting public key id %s was nil after parsing as a url", requestingPublicKeyIDString) log.Debugf(ctx, "http signature requesting public key id %s was nil after parsing as a url", requestingPublicKeyIDString)
c.AbortWithStatus(http.StatusUnauthorized) c.AbortWithStatus(http.StatusUnauthorized)
return return
} }
@ -68,11 +71,11 @@ func SignatureCheck(isURIBlocked func(context.Context, *url.URL) (bool, db.Error
// we managed to parse the url! // we managed to parse the url!
// if the domain is blocked we want to bail as early as possible // if the domain is blocked we want to bail as early as possible
if blocked, err := isURIBlocked(c.Request.Context(), requestingPublicKeyID); err != nil { if blocked, err := isURIBlocked(c.Request.Context(), requestingPublicKeyID); err != nil {
log.Errorf("could not tell if domain %s was blocked or not: %s", requestingPublicKeyID.Host, err) log.Errorf(ctx, "could not tell if domain %s was blocked or not: %s", requestingPublicKeyID.Host, err)
c.AbortWithStatus(http.StatusInternalServerError) c.AbortWithStatus(http.StatusInternalServerError)
return return
} else if blocked { } else if blocked {
log.Infof("domain %s is blocked", requestingPublicKeyID.Host) log.Infof(ctx, "domain %s is blocked", requestingPublicKeyID.Host)
c.AbortWithStatus(http.StatusForbidden) c.AbortWithStatus(http.StatusForbidden)
return return
} }

View file

@ -52,6 +52,7 @@
// Bearer token set (eg., for public instance information and so on). // Bearer token set (eg., for public instance information and so on).
func TokenCheck(dbConn db.DB, validateBearerToken func(r *http.Request) (oauth2.TokenInfo, error)) func(*gin.Context) { func TokenCheck(dbConn db.DB, validateBearerToken func(r *http.Request) (oauth2.TokenInfo, error)) func(*gin.Context) {
return func(c *gin.Context) { return func(c *gin.Context) {
// Acquire context from gin request.
ctx := c.Request.Context() ctx := c.Request.Context()
if c.Request.Header.Get("Authorization") == "" { if c.Request.Header.Get("Authorization") == "" {
@ -61,38 +62,38 @@ func TokenCheck(dbConn db.DB, validateBearerToken func(r *http.Request) (oauth2.
ti, err := validateBearerToken(c.Copy().Request) ti, err := validateBearerToken(c.Copy().Request)
if err != nil { if err != nil {
log.Debugf("token was passed in Authorization header but we could not validate it: %s", err) log.Debugf(ctx, "token was passed in Authorization header but we could not validate it: %s", err)
return return
} }
c.Set(oauth.SessionAuthorizedToken, ti) c.Set(oauth.SessionAuthorizedToken, ti)
// check for user-level token // check for user-level token
if userID := ti.GetUserID(); userID != "" { if userID := ti.GetUserID(); userID != "" {
log.Tracef("authenticated user %s with bearer token, scope is %s", userID, ti.GetScope()) log.Tracef(ctx, "authenticated user %s with bearer token, scope is %s", userID, ti.GetScope())
// fetch user for this token // fetch user for this token
user, err := dbConn.GetUserByID(ctx, userID) user, err := dbConn.GetUserByID(ctx, userID)
if err != nil { if err != nil {
if err != db.ErrNoEntries { if err != db.ErrNoEntries {
log.Errorf("database error looking for user with id %s: %s", userID, err) log.Errorf(ctx, "database error looking for user with id %s: %s", userID, err)
return return
} }
log.Warnf("no user found for userID %s", userID) log.Warnf(ctx, "no user found for userID %s", userID)
return return
} }
if user.ConfirmedAt.IsZero() { if user.ConfirmedAt.IsZero() {
log.Warnf("authenticated user %s has never confirmed thier email address", userID) log.Warnf(ctx, "authenticated user %s has never confirmed thier email address", userID)
return return
} }
if !*user.Approved { if !*user.Approved {
log.Warnf("authenticated user %s's account was never approved by an admin", userID) log.Warnf(ctx, "authenticated user %s's account was never approved by an admin", userID)
return return
} }
if *user.Disabled { if *user.Disabled {
log.Warnf("authenticated user %s's account was disabled'", userID) log.Warnf(ctx, "authenticated user %s's account was disabled'", userID)
return return
} }
@ -103,17 +104,17 @@ func TokenCheck(dbConn db.DB, validateBearerToken func(r *http.Request) (oauth2.
acct, err := dbConn.GetAccountByID(ctx, user.AccountID) acct, err := dbConn.GetAccountByID(ctx, user.AccountID)
if err != nil { if err != nil {
if err != db.ErrNoEntries { if err != db.ErrNoEntries {
log.Errorf("database error looking for account with id %s: %s", user.AccountID, err) log.Errorf(ctx, "database error looking for account with id %s: %s", user.AccountID, err)
return return
} }
log.Warnf("no account found for userID %s", userID) log.Warnf(ctx, "no account found for userID %s", userID)
return return
} }
user.Account = acct user.Account = acct
} }
if !user.Account.SuspendedAt.IsZero() { if !user.Account.SuspendedAt.IsZero() {
log.Warnf("authenticated user %s's account (accountId=%s) has been suspended", userID, user.AccountID) log.Warnf(ctx, "authenticated user %s's account (accountId=%s) has been suspended", userID, user.AccountID)
return return
} }
@ -122,16 +123,16 @@ func TokenCheck(dbConn db.DB, validateBearerToken func(r *http.Request) (oauth2.
// check for application token // check for application token
if clientID := ti.GetClientID(); clientID != "" { if clientID := ti.GetClientID(); clientID != "" {
log.Tracef("authenticated client %s with bearer token, scope is %s", clientID, ti.GetScope()) log.Tracef(ctx, "authenticated client %s with bearer token, scope is %s", clientID, ti.GetScope())
// fetch app for this token // fetch app for this token
app := &gtsmodel.Application{} app := &gtsmodel.Application{}
if err := dbConn.GetWhere(ctx, []db.Where{{Key: "client_id", Value: clientID}}, app); err != nil { if err := dbConn.GetWhere(ctx, []db.Where{{Key: "client_id", Value: clientID}}, app); err != nil {
if err != db.ErrNoEntries { if err != db.ErrNoEntries {
log.Errorf("database error looking for application with clientID %s: %s", clientID, err) log.Errorf(ctx, "database error looking for application with clientID %s: %s", clientID, err)
return return
} }
log.Warnf("no app found for client %s", clientID) log.Warnf(ctx, "no app found for client %s", clientID)
return return
} }
c.Set(oauth.SessionAuthorizedApplication, app) c.Set(oauth.SessionAuthorizedApplication, app)

View file

@ -103,12 +103,12 @@ func New(ctx context.Context, database db.Basic) Server {
srv := server.NewServer(sc, manager) srv := server.NewServer(sc, manager)
srv.SetInternalErrorHandler(func(err error) *errors.Response { srv.SetInternalErrorHandler(func(err error) *errors.Response {
log.Errorf("internal oauth error: %s", err) log.Errorf(nil, "internal oauth error: %s", err)
return nil return nil
}) })
srv.SetResponseErrorHandler(func(re *errors.Response) { srv.SetResponseErrorHandler(func(re *errors.Response) {
log.Errorf("internal response error: %s", re.Error) log.Errorf(nil, "internal response error: %s", re.Error)
}) })
srv.SetUserAuthorizationHandler(func(w http.ResponseWriter, r *http.Request) (string, error) { srv.SetUserAuthorizationHandler(func(w http.ResponseWriter, r *http.Request) (string, error) {
@ -272,7 +272,7 @@ func (s *s) GenerateUserAccessToken(ctx context.Context, ti oauth2.TokenInfo, cl
if authToken == nil { if authToken == nil {
return nil, errors.New("generated auth token was empty") return nil, errors.New("generated auth token was empty")
} }
log.Tracef("obtained auth token: %+v", authToken) log.Tracef(ctx, "obtained auth token: %+v", authToken)
accessToken, err := s.server.Manager.GenerateAccessToken(ctx, oauth2.AuthorizationCode, &oauth2.TokenGenerateRequest{ accessToken, err := s.server.Manager.GenerateAccessToken(ctx, oauth2.AuthorizationCode, &oauth2.TokenGenerateRequest{
ClientID: authToken.GetClientID(), ClientID: authToken.GetClientID(),
@ -287,7 +287,7 @@ func (s *s) GenerateUserAccessToken(ctx context.Context, ti oauth2.TokenInfo, cl
if accessToken == nil { if accessToken == nil {
return nil, errors.New("generated user-level access token was empty") return nil, errors.New("generated user-level access token was empty")
} }
log.Tracef("obtained user-level access token: %+v", accessToken) log.Tracef(ctx, "obtained user-level access token: %+v", accessToken)
return accessToken, nil return accessToken, nil
} }

View file

@ -53,12 +53,12 @@ func newTokenStore(ctx context.Context, db db.Basic) oauth2.TokenStore {
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
log.Info("breaking cleanloop") log.Info(ctx, "breaking cleanloop")
break cleanloop break cleanloop
case <-time.After(1 * time.Minute): case <-time.After(1 * time.Minute):
log.Trace("sweeping out old oauth entries broom broom") log.Trace(ctx, "sweeping out old oauth entries broom broom")
if err := ts.sweep(ctx); err != nil { if err := ts.sweep(ctx); err != nil {
log.Errorf("error while sweeping oauth entries: %s", err) log.Errorf(ctx, "error while sweeping oauth entries: %s", err)
} }
} }
} }

View file

@ -33,23 +33,23 @@ func (i *idp) HandleCallback(ctx context.Context, code string) (*Claims, gtserro
return nil, gtserror.NewErrorBadRequest(err, err.Error()) return nil, gtserror.NewErrorBadRequest(err, err.Error())
} }
log.Debug("exchanging code for oauth2token") log.Debug(ctx, "exchanging code for oauth2token")
oauth2Token, err := i.oauth2Config.Exchange(ctx, code) oauth2Token, err := i.oauth2Config.Exchange(ctx, code)
if err != nil { if err != nil {
err := fmt.Errorf("error exchanging code for oauth2token: %s", err) err := fmt.Errorf("error exchanging code for oauth2token: %s", err)
return nil, gtserror.NewErrorInternalError(err) return nil, gtserror.NewErrorInternalError(err)
} }
log.Debug("extracting id_token") log.Debug(ctx, "extracting id_token")
rawIDToken, ok := oauth2Token.Extra("id_token").(string) rawIDToken, ok := oauth2Token.Extra("id_token").(string)
if !ok { if !ok {
err := errors.New("no id_token in oauth2token") err := errors.New("no id_token in oauth2token")
return nil, gtserror.NewErrorBadRequest(err, err.Error()) return nil, gtserror.NewErrorBadRequest(err, err.Error())
} }
log.Debugf("raw id token: %s", rawIDToken) log.Debugf(ctx, "raw id token: %s", rawIDToken)
// Parse and verify ID Token payload. // Parse and verify ID Token payload.
log.Debug("verifying id_token") log.Debug(ctx, "verifying id_token")
idTokenVerifier := i.provider.Verifier(i.oidcConf) idTokenVerifier := i.provider.Verifier(i.oidcConf)
idToken, err := idTokenVerifier.Verify(ctx, rawIDToken) idToken, err := idTokenVerifier.Verify(ctx, rawIDToken)
if err != nil { if err != nil {
@ -57,7 +57,7 @@ func (i *idp) HandleCallback(ctx context.Context, code string) (*Claims, gtserro
return nil, gtserror.NewErrorUnauthorized(err, err.Error()) return nil, gtserror.NewErrorUnauthorized(err, err.Error())
} }
log.Debug("extracting claims from id_token") log.Debug(ctx, "extracting claims from id_token")
claims := &Claims{} claims := &Claims{}
if err := idToken.Claims(claims); err != nil { if err := idToken.Claims(claims); err != nil {
err := fmt.Errorf("could not parse claims from idToken: %s", err) err := fmt.Errorf("could not parse claims from idToken: %s", err)

View file

@ -59,13 +59,13 @@ func (p *processor) Create(ctx context.Context, applicationToken oauth2.TokenInf
reason = "" reason = ""
} }
log.Trace("creating new username and account") log.Trace(ctx, "creating new username and account")
user, err := p.db.NewSignup(ctx, form.Username, text.SanitizePlaintext(reason), approvalRequired, form.Email, form.Password, form.IP, form.Locale, application.ID, false, "", false) user, err := p.db.NewSignup(ctx, form.Username, text.SanitizePlaintext(reason), approvalRequired, form.Email, form.Password, form.IP, form.Locale, application.ID, false, "", false)
if err != nil { if err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error creating new signup in the database: %s", err)) return nil, gtserror.NewErrorInternalError(fmt.Errorf("error creating new signup in the database: %s", err))
} }
log.Tracef("generating a token for user %s with account %s and application %s", user.ID, user.AccountID, application.ID) log.Tracef(ctx, "generating a token for user %s with account %s and application %s", user.ID, user.AccountID, application.ID)
accessToken, err := p.oauthServer.GenerateUserAccessToken(ctx, applicationToken, application.ClientSecret, user.ID) accessToken, err := p.oauthServer.GenerateUserAccessToken(ctx, applicationToken, application.ClientSecret, user.ID)
if err != nil { if err != nil {
return nil, gtserror.NewErrorInternalError(fmt.Errorf("error creating new access token for user %s: %s", user.ID, err)) return nil, gtserror.NewErrorInternalError(fmt.Errorf("error creating new access token for user %s: %s", user.ID, err))

View file

@ -64,7 +64,7 @@ func (p *processor) Delete(ctx context.Context, account *gtsmodel.Account, origi
}) })
} }
l := log.WithFields(fields...) l := log.WithContext(ctx).WithFields(fields...)
l.Trace("beginning account delete process") l.Trace("beginning account delete process")
// 1. Delete account's application(s), clients, and oauth tokens // 1. Delete account's application(s), clients, and oauth tokens

View file

@ -97,7 +97,7 @@ func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form
} }
account.AvatarMediaAttachmentID = avatarInfo.ID account.AvatarMediaAttachmentID = avatarInfo.ID
account.AvatarMediaAttachment = avatarInfo account.AvatarMediaAttachment = avatarInfo
log.Tracef("new avatar info for account %s is %+v", account.ID, avatarInfo) log.Tracef(ctx, "new avatar info for account %s is %+v", account.ID, avatarInfo)
} }
if form.Header != nil && form.Header.Size != 0 { if form.Header != nil && form.Header.Size != 0 {
@ -107,7 +107,7 @@ func (p *processor) Update(ctx context.Context, account *gtsmodel.Account, form
} }
account.HeaderMediaAttachmentID = headerInfo.ID account.HeaderMediaAttachmentID = headerInfo.ID
account.HeaderMediaAttachment = headerInfo account.HeaderMediaAttachment = headerInfo
log.Tracef("new header info for account %s is %+v", account.ID, headerInfo) log.Tracef(ctx, "new header info for account %s is %+v", account.ID, headerInfo)
} }
if form.Locked != nil { if form.Locked != nil {

View file

@ -89,9 +89,10 @@ func (p *processor) DomainBlockCreate(ctx context.Context, account *gtsmodel.Acc
// 2. Delete the instance account for that instance if it exists. // 2. Delete the instance account for that instance if it exists.
// 3. Select all accounts from this instance and pass them through the delete functionality of the processor. // 3. Select all accounts from this instance and pass them through the delete functionality of the processor.
func (p *processor) initiateDomainBlockSideEffects(ctx context.Context, account *gtsmodel.Account, block *gtsmodel.DomainBlock) { func (p *processor) initiateDomainBlockSideEffects(ctx context.Context, account *gtsmodel.Account, block *gtsmodel.DomainBlock) {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"domain", block.Domain}, WithFields(kv.Fields{
}...) {"domain", block.Domain},
}...)
l.Debug("processing domain block side effects") l.Debug("processing domain block side effects")

View file

@ -35,12 +35,12 @@ func (p *processor) MediaRefetch(ctx context.Context, requestingAccount *gtsmode
} }
go func() { go func() {
log.Info("starting emoji refetch") log.Info(ctx, "starting emoji refetch")
refetched, err := p.mediaManager.RefetchEmojis(context.Background(), domain, transport.DereferenceMedia) refetched, err := p.mediaManager.RefetchEmojis(context.Background(), domain, transport.DereferenceMedia)
if err != nil { if err != nil {
log.Errorf("error refetching emojis: %s", err) log.Errorf(ctx, "error refetching emojis: %s", err)
} else { } else {
log.Infof("refetched %d emojis from remote", refetched) log.Infof(ctx, "refetched %d emojis from remote", refetched)
} }
}() }()

View file

@ -50,7 +50,7 @@ func (p *processor) ProcessFromClientAPI(ctx context.Context, clientMsg messages
} }
// Log this federated message // Log this federated message
l := log.WithFields(fields...) l := log.WithContext(ctx).WithFields(fields...)
l.Info("processing from client") l.Info("processing from client")
switch clientMsg.APActivityType { switch clientMsg.APActivityType {

View file

@ -59,7 +59,7 @@ func (p *processor) ProcessFromFederator(ctx context.Context, federatorMsg messa
} }
// Log this federated message // Log this federated message
l := log.WithFields(fields...) l := log.WithContext(ctx).WithFields(fields...)
l.Info("processing from federator") l.Info("processing from federator")
switch federatorMsg.APActivityType { switch federatorMsg.APActivityType {

View file

@ -40,7 +40,7 @@ func (p *processor) GetCustomEmojis(ctx context.Context) ([]*apimodel.Emoji, gts
for _, gtsEmoji := range emojis { for _, gtsEmoji := range emojis {
apiEmoji, err := p.tc.EmojiToAPIEmoji(ctx, gtsEmoji) apiEmoji, err := p.tc.EmojiToAPIEmoji(ctx, gtsEmoji)
if err != nil { if err != nil {
log.Errorf("error converting emoji with id %s: %s", gtsEmoji.ID, err) log.Errorf(ctx, "error converting emoji with id %s: %s", gtsEmoji.ID, err)
continue continue
} }
apiEmojis = append(apiEmojis, &apiEmoji) apiEmojis = append(apiEmojis, &apiEmoji)

View file

@ -46,7 +46,7 @@ func (p *processor) NotificationsGet(ctx context.Context, authed *oauth.Auth, ex
for i, n := range notifs { for i, n := range notifs {
item, err := p.tc.NotificationToAPINotification(ctx, n) item, err := p.tc.NotificationToAPINotification(ctx, n)
if err != nil { if err != nil {
log.Debugf("got an error converting a notification to api, will skip it: %s", err) log.Debugf(ctx, "got an error converting a notification to api, will skip it: %s", err)
continue continue
} }

View file

@ -57,7 +57,8 @@ func (p *processor) SearchGet(ctx context.Context, authed *oauth.Auth, search *a
return nil, gtserror.NewErrorBadRequest(err, err.Error()) return nil, gtserror.NewErrorBadRequest(err, err.Error())
} }
l := log.WithFields(kv.Fields{{"query", query}}...) l := log.WithContext(ctx).
WithFields(kv.Fields{{"query", query}}...)
searchResult := &apimodel.SearchResult{ searchResult := &apimodel.SearchResult{
Accounts: []apimodel.Account{}, Accounts: []apimodel.Account{},

View file

@ -72,7 +72,7 @@ func StatusFilterFunction(database db.DB, filter visibility.Filter) timeline.Fil
timelineable, err := filter.StatusHometimelineable(ctx, status, requestingAccount) timelineable, err := filter.StatusHometimelineable(ctx, status, requestingAccount)
if err != nil { if err != nil {
log.Warnf("error checking hometimelineability of status %s for account %s: %s", status.ID, timelineAccountID, err) log.Warnf(ctx, "error checking hometimelineability of status %s for account %s: %s", status.ID, timelineAccountID, err)
} }
return timelineable, nil // we don't return the error here because we want to just skip this item if something goes wrong return timelineable, nil // we don't return the error here because we want to just skip this item if something goes wrong
@ -257,7 +257,7 @@ func (p *processor) filterPublicStatuses(ctx context.Context, authed *oauth.Auth
targetAccount := &gtsmodel.Account{} targetAccount := &gtsmodel.Account{}
if err := p.db.GetByID(ctx, s.AccountID, targetAccount); err != nil { if err := p.db.GetByID(ctx, s.AccountID, targetAccount); err != nil {
if err == db.ErrNoEntries { if err == db.ErrNoEntries {
log.Debugf("filterPublicStatuses: skipping status %s because account %s can't be found in the db", s.ID, s.AccountID) log.Debugf(ctx, "skipping status %s because account %s can't be found in the db", s.ID, s.AccountID)
continue continue
} }
return nil, gtserror.NewErrorInternalError(fmt.Errorf("filterPublicStatuses: error getting status author: %s", err)) return nil, gtserror.NewErrorInternalError(fmt.Errorf("filterPublicStatuses: error getting status author: %s", err))
@ -265,7 +265,7 @@ func (p *processor) filterPublicStatuses(ctx context.Context, authed *oauth.Auth
timelineable, err := p.filter.StatusPublictimelineable(ctx, s, authed.Account) timelineable, err := p.filter.StatusPublictimelineable(ctx, s, authed.Account)
if err != nil { if err != nil {
log.Debugf("filterPublicStatuses: skipping status %s because of an error checking status visibility: %s", s.ID, err) log.Debugf(ctx, "skipping status %s because of an error checking status visibility: %s", s.ID, err)
continue continue
} }
if !timelineable { if !timelineable {
@ -274,7 +274,7 @@ func (p *processor) filterPublicStatuses(ctx context.Context, authed *oauth.Auth
apiStatus, err := p.tc.StatusToAPIStatus(ctx, s, authed.Account) apiStatus, err := p.tc.StatusToAPIStatus(ctx, s, authed.Account)
if err != nil { if err != nil {
log.Debugf("filterPublicStatuses: skipping status %s because it couldn't be converted to its api representation: %s", s.ID, err) log.Debugf(ctx, "skipping status %s because it couldn't be converted to its api representation: %s", s.ID, err)
continue continue
} }
@ -290,7 +290,7 @@ func (p *processor) filterFavedStatuses(ctx context.Context, authed *oauth.Auth,
targetAccount := &gtsmodel.Account{} targetAccount := &gtsmodel.Account{}
if err := p.db.GetByID(ctx, s.AccountID, targetAccount); err != nil { if err := p.db.GetByID(ctx, s.AccountID, targetAccount); err != nil {
if err == db.ErrNoEntries { if err == db.ErrNoEntries {
log.Debugf("filterFavedStatuses: skipping status %s because account %s can't be found in the db", s.ID, s.AccountID) log.Debugf(ctx, "skipping status %s because account %s can't be found in the db", s.ID, s.AccountID)
continue continue
} }
return nil, gtserror.NewErrorInternalError(fmt.Errorf("filterPublicStatuses: error getting status author: %s", err)) return nil, gtserror.NewErrorInternalError(fmt.Errorf("filterPublicStatuses: error getting status author: %s", err))
@ -298,7 +298,7 @@ func (p *processor) filterFavedStatuses(ctx context.Context, authed *oauth.Auth,
timelineable, err := p.filter.StatusVisible(ctx, s, authed.Account) timelineable, err := p.filter.StatusVisible(ctx, s, authed.Account)
if err != nil { if err != nil {
log.Debugf("filterFavedStatuses: skipping status %s because of an error checking status visibility: %s", s.ID, err) log.Debugf(ctx, "skipping status %s because of an error checking status visibility: %s", s.ID, err)
continue continue
} }
if !timelineable { if !timelineable {
@ -307,7 +307,7 @@ func (p *processor) filterFavedStatuses(ctx context.Context, authed *oauth.Auth,
apiStatus, err := p.tc.StatusToAPIStatus(ctx, s, authed.Account) apiStatus, err := p.tc.StatusToAPIStatus(ctx, s, authed.Account)
if err != nil { if err != nil {
log.Debugf("filterFavedStatuses: skipping status %s because it couldn't be converted to its api representation: %s", s.ID, err) log.Debugf(ctx, "skipping status %s because it couldn't be converted to its api representation: %s", s.ID, err)
continue continue
} }

View file

@ -32,11 +32,11 @@
) )
func (p *processor) OpenStreamForAccount(ctx context.Context, account *gtsmodel.Account, streamTimeline string) (*stream.Stream, gtserror.WithCode) { func (p *processor) OpenStreamForAccount(ctx context.Context, account *gtsmodel.Account, streamTimeline string) (*stream.Stream, gtserror.WithCode) {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
WithFields(kv.Fields{
{"account", account.ID}, {"account", account.ID},
{"streamType", streamTimeline}, {"streamType", streamTimeline},
}...) }...)
l.Debug("received open stream request") l.Debug("received open stream request")
// each stream needs a unique ID so we know to close it // each stream needs a unique ID so we know to close it

View file

@ -101,10 +101,10 @@ func (r *router) Start() {
) )
// Start the LetsEncrypt autocert manager HTTP server. // Start the LetsEncrypt autocert manager HTTP server.
log.Infof("letsencrypt listening on %s", srv.Addr) log.Infof(nil, "letsencrypt listening on %s", srv.Addr)
if err := srv.ListenAndServe(); err != nil && if err := srv.ListenAndServe(); err != nil &&
err != http.ErrServerClosed { err != http.ErrServerClosed {
log.Fatalf("letsencrypt: listen: %s", err) log.Fatalf(nil, "letsencrypt: listen: %s", err)
} }
}() }()
@ -119,23 +119,23 @@ func (r *router) Start() {
r.srv.Handler = debug.WithPprof(r.srv.Handler) r.srv.Handler = debug.WithPprof(r.srv.Handler)
if debug.DEBUG { if debug.DEBUG {
// Profiling requires timeouts longer than 30s, so reset these. // Profiling requires timeouts longer than 30s, so reset these.
log.Warn("resetting http.Server{} timeout to support profiling") log.Warn(nil, "resetting http.Server{} timeout to support profiling")
r.srv.ReadTimeout = 0 r.srv.ReadTimeout = 0
r.srv.WriteTimeout = 0 r.srv.WriteTimeout = 0
} }
// Start the main listener. // Start the main listener.
go func() { go func() {
log.Infof("listening on %s", r.srv.Addr) log.Infof(nil, "listening on %s", r.srv.Addr)
if err := listen(); err != nil && err != http.ErrServerClosed { if err := listen(); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %s", err) log.Fatalf(nil, "listen: %s", err)
} }
}() }()
} }
// Stop shuts down the router nicely // Stop shuts down the router nicely
func (r *router) Stop(ctx context.Context) error { func (r *router) Stop(ctx context.Context) error {
log.Infof("shutting down http router with %s grace period", shutdownTimeout) log.Infof(nil, "shutting down http router with %s grace period", shutdownTimeout)
timeout, cancel := context.WithTimeout(ctx, shutdownTimeout) timeout, cancel := context.WithTimeout(ctx, shutdownTimeout)
defer cancel() defer cancel()
@ -143,7 +143,7 @@ func (r *router) Stop(ctx context.Context) error {
return fmt.Errorf("error shutting down http router: %s", err) return fmt.Errorf("error shutting down http router: %s", err)
} }
log.Info("http router closed connections and shut down gracefully") log.Info(nil, "http router closed connections and shut down gracefully")
return nil return nil
} }

View file

@ -87,7 +87,7 @@ func noescapeAttr(str string) template.HTMLAttr {
func timestamp(stamp string) string { func timestamp(stamp string) string {
t, err := util.ParseISO8601(stamp) t, err := util.ParseISO8601(stamp)
if err != nil { if err != nil {
log.Errorf("error parsing timestamp %s: %s", stamp, err) log.Errorf(nil, "error parsing timestamp %s: %s", stamp, err)
return badTimestamp return badTimestamp
} }
@ -110,7 +110,7 @@ func timestamp(stamp string) string {
func timestampPrecise(stamp string) string { func timestampPrecise(stamp string) string {
t, err := util.ParseISO8601(stamp) t, err := util.ParseISO8601(stamp)
if err != nil { if err != nil {
log.Errorf("error parsing timestamp %s: %s", stamp, err) log.Errorf(nil, "error parsing timestamp %s: %s", stamp, err)
return badTimestamp return badTimestamp
} }
return t.Local().Format(dateYearTime) return t.Local().Format(dateYearTime)
@ -119,7 +119,7 @@ func timestampPrecise(stamp string) string {
func timestampVague(stamp string) string { func timestampVague(stamp string) string {
t, err := util.ParseISO8601(stamp) t, err := util.ParseISO8601(stamp)
if err != nil { if err != nil {
log.Errorf("error parsing timestamp %s: %s", stamp, err) log.Errorf(nil, "error parsing timestamp %s: %s", stamp, err)
return badTimestamp return badTimestamp
} }
return t.Format(monthYear) return t.Format(monthYear)

View file

@ -128,8 +128,9 @@ func NewFileStorage() (*Driver, error) {
return nil, fmt.Errorf("error opening disk storage: %w", err) return nil, fmt.Errorf("error opening disk storage: %w", err)
} }
// Perform an initial storage clean to delete old dirs.
if err := disk.Clean(context.Background()); err != nil { if err := disk.Clean(context.Background()); err != nil {
log.Errorf("error performing storage cleanup: %v", err) log.Errorf(nil, "error performing storage cleanup: %v", err)
} }
return &Driver{ return &Driver{

View file

@ -57,7 +57,7 @@ func (f *formatter) FromPlainEmojiOnly(ctx context.Context, pmf gtsmodel.ParseMe
var htmlContentBytes bytes.Buffer var htmlContentBytes bytes.Buffer
err := md.Convert([]byte(plain), &htmlContentBytes) err := md.Convert([]byte(plain), &htmlContentBytes)
if err != nil { if err != nil {
log.Errorf("error formatting plaintext to HTML: %s", err) log.Errorf(ctx, "error formatting plaintext to HTML: %s", err)
} }
result.HTML = htmlContentBytes.String() result.HTML = htmlContentBytes.String()
@ -65,7 +65,10 @@ func (f *formatter) FromPlainEmojiOnly(ctx context.Context, pmf gtsmodel.ParseMe
result.HTML = SanitizeHTML(result.HTML) result.HTML = SanitizeHTML(result.HTML)
// shrink ray // shrink ray
result.HTML = minifyHTML(result.HTML) result.HTML, err = m.String("text/html", result.HTML)
if err != nil {
log.Errorf(ctx, "error minifying HTML: %s", err)
}
return result return result
} }

View file

@ -53,9 +53,11 @@ type emoji struct {
Segment text.Segment Segment text.Segment
} }
var kindMention = ast.NewNodeKind("Mention") var (
var kindHashtag = ast.NewNodeKind("Hashtag") kindMention = ast.NewNodeKind("Mention")
var kindEmoji = ast.NewNodeKind("Emoji") kindHashtag = ast.NewNodeKind("Hashtag")
kindEmoji = ast.NewNodeKind("Emoji")
)
func (n *mention) Kind() ast.NodeKind { func (n *mention) Kind() ast.NodeKind {
return kindMention return kindMention
@ -106,14 +108,11 @@ func newEmoji(s text.Segment) *emoji {
} }
// mentionParser and hashtagParser fulfil the goldmark parser.InlineParser interface. // mentionParser and hashtagParser fulfil the goldmark parser.InlineParser interface.
type mentionParser struct { type mentionParser struct{}
}
type hashtagParser struct { type hashtagParser struct{}
}
type emojiParser struct { type emojiParser struct{}
}
func (p *mentionParser) Trigger() []byte { func (p *mentionParser) Trigger() []byte {
return []byte{'@'} return []byte{'@'}
@ -239,7 +238,7 @@ func (r *customRenderer) renderMention(w mdutil.BufWriter, source []byte, node a
n, ok := node.(*mention) // this function is only registered for kindMention n, ok := node.(*mention) // this function is only registered for kindMention
if !ok { if !ok {
log.Errorf("type assertion failed") log.Panic(nil, "type assertion failed")
} }
text := string(n.Segment.Value(source)) text := string(n.Segment.Value(source))
@ -247,7 +246,7 @@ func (r *customRenderer) renderMention(w mdutil.BufWriter, source []byte, node a
// we don't have much recourse if this fails // we don't have much recourse if this fails
if _, err := w.WriteString(html); err != nil { if _, err := w.WriteString(html); err != nil {
log.Errorf("error writing HTML: %s", err) log.Errorf(nil, "error writing HTML: %s", err)
} }
return ast.WalkSkipChildren, nil return ast.WalkSkipChildren, nil
} }
@ -259,7 +258,7 @@ func (r *customRenderer) renderHashtag(w mdutil.BufWriter, source []byte, node a
n, ok := node.(*hashtag) // this function is only registered for kindHashtag n, ok := node.(*hashtag) // this function is only registered for kindHashtag
if !ok { if !ok {
log.Errorf("type assertion failed") log.Panic(nil, "type assertion failed")
} }
text := string(n.Segment.Value(source)) text := string(n.Segment.Value(source))
@ -268,7 +267,7 @@ func (r *customRenderer) renderHashtag(w mdutil.BufWriter, source []byte, node a
_, err := w.WriteString(html) _, err := w.WriteString(html)
// we don't have much recourse if this fails // we don't have much recourse if this fails
if err != nil { if err != nil {
log.Errorf("error writing HTML: %s", err) log.Errorf(nil, "error writing HTML: %s", err)
} }
return ast.WalkSkipChildren, nil return ast.WalkSkipChildren, nil
} }
@ -281,7 +280,7 @@ func (r *customRenderer) renderEmoji(w mdutil.BufWriter, source []byte, node ast
n, ok := node.(*emoji) // this function is only registered for kindEmoji n, ok := node.(*emoji) // this function is only registered for kindEmoji
if !ok { if !ok {
log.Errorf("type assertion failed") log.Panic(nil, "type assertion failed")
} }
text := string(n.Segment.Value(source)) text := string(n.Segment.Value(source))
shortcode := text[1 : len(text)-1] shortcode := text[1 : len(text)-1]
@ -289,7 +288,7 @@ func (r *customRenderer) renderEmoji(w mdutil.BufWriter, source []byte, node ast
emoji, err := r.f.db.GetEmojiByShortcodeDomain(r.ctx, shortcode, "") emoji, err := r.f.db.GetEmojiByShortcodeDomain(r.ctx, shortcode, "")
if err != nil { if err != nil {
if err != db.ErrNoEntries { if err != db.ErrNoEntries {
log.Errorf("error getting local emoji with shortcode %s: %s", shortcode, err) log.Errorf(nil, "error getting local emoji with shortcode %s: %s", shortcode, err)
} }
} else if *emoji.VisibleInPicker && !*emoji.Disabled { } else if *emoji.VisibleInPicker && !*emoji.Disabled {
listed := false listed := false
@ -306,7 +305,7 @@ func (r *customRenderer) renderEmoji(w mdutil.BufWriter, source []byte, node ast
// we don't have much recourse if this fails // we don't have much recourse if this fails
if _, err := w.WriteString(text); err != nil { if _, err := w.WriteString(text); err != nil {
log.Errorf("error writing HTML: %s", err) log.Errorf(nil, "error writing HTML: %s", err)
} }
return ast.WalkSkipChildren, nil return ast.WalkSkipChildren, nil
} }

View file

@ -53,7 +53,7 @@ func (f *formatter) FromMarkdown(ctx context.Context, pmf gtsmodel.ParseMentionF
var htmlContentBytes bytes.Buffer var htmlContentBytes bytes.Buffer
err := md.Convert([]byte(markdownText), &htmlContentBytes) err := md.Convert([]byte(markdownText), &htmlContentBytes)
if err != nil { if err != nil {
log.Errorf("error formatting markdown to HTML: %s", err) log.Errorf(ctx, "error formatting markdown to HTML: %s", err)
} }
result.HTML = htmlContentBytes.String() result.HTML = htmlContentBytes.String()
@ -61,7 +61,10 @@ func (f *formatter) FromMarkdown(ctx context.Context, pmf gtsmodel.ParseMentionF
result.HTML = SanitizeHTML(result.HTML) result.HTML = SanitizeHTML(result.HTML)
// shrink ray // shrink ray
result.HTML = minifyHTML(result.HTML) result.HTML, err = m.String("text/html", result.HTML)
if err != nil {
log.Errorf(ctx, "error minifying HTML: %s", err)
}
return result return result
} }

View file

@ -19,27 +19,16 @@
package text package text
import ( import (
"github.com/superseriousbusiness/gotosocial/internal/log"
"github.com/tdewolff/minify/v2" "github.com/tdewolff/minify/v2"
"github.com/tdewolff/minify/v2/html" "github.com/tdewolff/minify/v2/html"
) )
var ( // m is the global minify instance.
m *minify.M var m = func() *minify.M {
) m := minify.New()
m.Add("text/html", &html.Minifier{
func minifyHTML(content string) string { KeepEndTags: true,
if m == nil { KeepQuotes: true,
m = minify.New() })
m.Add("text/html", &html.Minifier{ return m
KeepEndTags: true, }()
KeepQuotes: true,
})
}
minified, err := m.String("text/html", content)
if err != nil {
log.Errorf("error minifying HTML: %s", err)
}
return minified
}

View file

@ -60,7 +60,7 @@ func (f *formatter) FromPlain(ctx context.Context, pmf gtsmodel.ParseMentionFunc
var htmlContentBytes bytes.Buffer var htmlContentBytes bytes.Buffer
err := md.Convert([]byte(plain), &htmlContentBytes) err := md.Convert([]byte(plain), &htmlContentBytes)
if err != nil { if err != nil {
log.Errorf("error formatting plaintext to HTML: %s", err) log.Errorf(ctx, "error formatting plaintext to HTML: %s", err)
} }
result.HTML = htmlContentBytes.String() result.HTML = htmlContentBytes.String()
@ -68,7 +68,10 @@ func (f *formatter) FromPlain(ctx context.Context, pmf gtsmodel.ParseMentionFunc
result.HTML = SanitizeHTML(result.HTML) result.HTML = SanitizeHTML(result.HTML)
// shrink ray // shrink ray
result.HTML = minifyHTML(result.HTML) result.HTML, err = m.String("text/html", result.HTML)
if err != nil {
log.Errorf(ctx, "error minifying HTML: %s", err)
}
return result return result
} }

View file

@ -20,11 +20,12 @@
import ( import (
"errors" "errors"
"strings"
"github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/log" "github.com/superseriousbusiness/gotosocial/internal/log"
"github.com/superseriousbusiness/gotosocial/internal/util" "github.com/superseriousbusiness/gotosocial/internal/util"
"golang.org/x/text/unicode/norm" "golang.org/x/text/unicode/norm"
"strings"
) )
const ( const (
@ -39,13 +40,13 @@
func (r *customRenderer) replaceMention(text string) string { func (r *customRenderer) replaceMention(text string) string {
menchie, err := r.parseMention(r.ctx, text, r.accountID, r.statusID) menchie, err := r.parseMention(r.ctx, text, r.accountID, r.statusID)
if err != nil { if err != nil {
log.Errorf("error parsing mention %s from status: %s", text, err) log.Errorf(nil, "error parsing mention %s from status: %s", text, err)
return text return text
} }
if r.statusID != "" { if r.statusID != "" {
if err := r.f.db.Put(r.ctx, menchie); err != nil { if err := r.f.db.Put(r.ctx, menchie); err != nil {
log.Errorf("error putting mention in db: %s", err) log.Errorf(nil, "error putting mention in db: %s", err)
return text return text
} }
} }
@ -66,7 +67,7 @@ func (r *customRenderer) replaceMention(text string) string {
if menchie.TargetAccount == nil { if menchie.TargetAccount == nil {
a, err := r.f.db.GetAccountByID(r.ctx, menchie.TargetAccountID) a, err := r.f.db.GetAccountByID(r.ctx, menchie.TargetAccountID)
if err != nil { if err != nil {
log.Errorf("error getting account with id %s from the db: %s", menchie.TargetAccountID, err) log.Errorf(nil, "error getting account with id %s from the db: %s", menchie.TargetAccountID, err)
return text return text
} }
menchie.TargetAccount = a menchie.TargetAccount = a
@ -105,7 +106,7 @@ func (r *customRenderer) replaceHashtag(text string) string {
tag, err := r.f.db.TagStringToTag(r.ctx, normalized, r.accountID) tag, err := r.f.db.TagStringToTag(r.ctx, normalized, r.accountID)
if err != nil { if err != nil {
log.Errorf("error generating hashtags from status: %s", err) log.Errorf(nil, "error generating hashtags from status: %s", err)
return text return text
} }
@ -121,7 +122,7 @@ func (r *customRenderer) replaceHashtag(text string) string {
err = r.f.db.Put(r.ctx, tag) err = r.f.db.Put(r.ctx, tag)
if err != nil { if err != nil {
if !errors.Is(err, db.ErrAlreadyExists) { if !errors.Is(err, db.ErrAlreadyExists) {
log.Errorf("error putting tags in db: %s", err) log.Errorf(nil, "error putting tags in db: %s", err)
return text return text
} }
} }

View file

@ -38,14 +38,15 @@ func (t *timeline) LastGot() time.Time {
} }
func (t *timeline) Get(ctx context.Context, amount int, maxID string, sinceID string, minID string, prepareNext bool) ([]Preparable, error) { func (t *timeline) Get(ctx context.Context, amount int, maxID string, sinceID string, minID string, prepareNext bool) ([]Preparable, error) {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"accountID", t.accountID}, WithFields(kv.Fields{
{"amount", amount}, {"accountID", t.accountID},
{"maxID", maxID}, {"amount", amount},
{"sinceID", sinceID}, {"maxID", maxID},
{"minID", minID}, {"sinceID", sinceID},
}...) {"minID", minID},
l.Debug("entering get and updating t.lastGot") }...)
l.Trace("entering get and updating t.lastGot")
// regardless of what happens below, update the // regardless of what happens below, update the
// last time Get was called for this timeline // last time Get was called for this timeline
@ -154,11 +155,12 @@ func (t *timeline) getXFromTop(ctx context.Context, amount int) ([]Preparable, e
// //
// This corresponds to an api call to /timelines/home?max_id=WHATEVER // This corresponds to an api call to /timelines/home?max_id=WHATEVER
func (t *timeline) getXBehindID(ctx context.Context, amount int, behindID string, attempts *int) ([]Preparable, error) { func (t *timeline) getXBehindID(ctx context.Context, amount int, behindID string, attempts *int) ([]Preparable, error) {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"amount", amount}, WithFields(kv.Fields{
{"behindID", behindID}, {"amount", amount},
{"attempts", attempts}, {"behindID", behindID},
}...) {"attempts", attempts},
}...)
newAttempts := *attempts newAttempts := *attempts
newAttempts++ newAttempts++

View file

@ -35,58 +35,9 @@ func (t *timeline) ItemIndexLength(ctx context.Context) int {
return t.indexedItems.data.Len() return t.indexedItems.data.Len()
} }
// func (t *timeline) indexBefore(ctx context.Context, itemID string, amount int) error {
// l := log.WithFields(kv.Fields{{"amount", amount}}...)
// // lazily initialize index if it hasn't been done already
// if t.indexedItems.data == nil {
// t.indexedItems.data = &list.List{}
// t.indexedItems.data.Init()
// }
// toIndex := []Timelineable{}
// offsetID := itemID
// l.Trace("entering grabloop")
// grabloop:
// for i := 0; len(toIndex) < amount && i < 5; i++ { // try the grabloop 5 times only
// // first grab items using the caller-provided grab function
// l.Trace("grabbing...")
// items, stop, err := t.grabFunction(ctx, t.accountID, "", "", offsetID, amount)
// if err != nil {
// return err
// }
// if stop {
// break grabloop
// }
// l.Trace("filtering...")
// // now filter each item using the caller-provided filter function
// for _, item := range items {
// shouldIndex, err := t.filterFunction(ctx, t.accountID, item)
// if err != nil {
// return err
// }
// if shouldIndex {
// toIndex = append(toIndex, item)
// }
// offsetID = item.GetID()
// }
// }
// l.Trace("left grabloop")
// // index the items we got
// for _, s := range toIndex {
// if _, err := t.IndexOne(ctx, s.GetID(), s.GetBoostOfID(), s.GetAccountID(), s.GetBoostOfAccountID()); err != nil {
// return fmt.Errorf("indexBefore: error indexing item with id %s: %s", s.GetID(), err)
// }
// }
// return nil
// }
func (t *timeline) indexBehind(ctx context.Context, itemID string, amount int) error { func (t *timeline) indexBehind(ctx context.Context, itemID string, amount int) error {
l := log.WithFields(kv.Fields{{"amount", amount}}...) l := log.WithContext(ctx).
WithFields(kv.Fields{{"amount", amount}}...)
// lazily initialize index if it hasn't been done already // lazily initialize index if it hasn't been done already
if t.indexedItems.data == nil { if t.indexedItems.data == nil {

View file

@ -134,10 +134,11 @@ func (m *manager) Stop() error {
} }
func (m *manager) Ingest(ctx context.Context, item Timelineable, timelineAccountID string) (bool, error) { func (m *manager) Ingest(ctx context.Context, item Timelineable, timelineAccountID string) (bool, error) {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"timelineAccountID", timelineAccountID}, WithFields(kv.Fields{
{"itemID", item.GetID()}, {"timelineAccountID", timelineAccountID},
}...) {"itemID", item.GetID()},
}...)
t, err := m.getOrCreateTimeline(ctx, timelineAccountID) t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
if err != nil { if err != nil {
@ -149,10 +150,11 @@ func (m *manager) Ingest(ctx context.Context, item Timelineable, timelineAccount
} }
func (m *manager) IngestAndPrepare(ctx context.Context, item Timelineable, timelineAccountID string) (bool, error) { func (m *manager) IngestAndPrepare(ctx context.Context, item Timelineable, timelineAccountID string) (bool, error) {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"timelineAccountID", timelineAccountID}, WithFields(kv.Fields{
{"itemID", item.GetID()}, {"timelineAccountID", timelineAccountID},
}...) {"itemID", item.GetID()},
}...)
t, err := m.getOrCreateTimeline(ctx, timelineAccountID) t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
if err != nil { if err != nil {
@ -164,10 +166,11 @@ func (m *manager) IngestAndPrepare(ctx context.Context, item Timelineable, timel
} }
func (m *manager) Remove(ctx context.Context, timelineAccountID string, itemID string) (int, error) { func (m *manager) Remove(ctx context.Context, timelineAccountID string, itemID string) (int, error) {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"timelineAccountID", timelineAccountID}, WithFields(kv.Fields{
{"itemID", itemID}, {"timelineAccountID", timelineAccountID},
}...) {"itemID", itemID},
}...)
t, err := m.getOrCreateTimeline(ctx, timelineAccountID) t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
if err != nil { if err != nil {
@ -179,7 +182,8 @@ func (m *manager) Remove(ctx context.Context, timelineAccountID string, itemID s
} }
func (m *manager) GetTimeline(ctx context.Context, timelineAccountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]Preparable, error) { func (m *manager) GetTimeline(ctx context.Context, timelineAccountID string, maxID string, sinceID string, minID string, limit int, local bool) ([]Preparable, error) {
l := log.WithFields(kv.Fields{{"timelineAccountID", timelineAccountID}}...) l := log.WithContext(ctx).
WithFields(kv.Fields{{"timelineAccountID", timelineAccountID}}...)
t, err := m.getOrCreateTimeline(ctx, timelineAccountID) t, err := m.getOrCreateTimeline(ctx, timelineAccountID)
if err != nil { if err != nil {

View file

@ -31,7 +31,8 @@
) )
func (t *timeline) PrepareFromTop(ctx context.Context, amount int) error { func (t *timeline) PrepareFromTop(ctx context.Context, amount int) error {
l := log.WithFields(kv.Fields{{"amount", amount}}...) l := log.WithContext(ctx).
WithFields(kv.Fields{{"amount", amount}}...)
// lazily initialize prepared posts if it hasn't been done already // lazily initialize prepared posts if it hasn't been done already
if t.preparedItems.data == nil { if t.preparedItems.data == nil {
@ -85,12 +86,13 @@ func (t *timeline) PrepareFromTop(ctx context.Context, amount int) error {
} }
func (t *timeline) prepareNextQuery(ctx context.Context, amount int, maxID string, sinceID string, minID string) error { func (t *timeline) prepareNextQuery(ctx context.Context, amount int, maxID string, sinceID string, minID string) error {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"amount", amount}, WithFields(kv.Fields{
{"maxID", maxID}, {"amount", amount},
{"sinceID", sinceID}, {"maxID", maxID},
{"minID", minID}, {"sinceID", sinceID},
}...) {"minID", minID},
}...)
var err error var err error
switch { switch {

View file

@ -28,10 +28,11 @@
) )
func (t *timeline) Remove(ctx context.Context, statusID string) (int, error) { func (t *timeline) Remove(ctx context.Context, statusID string) (int, error) {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"accountTimeline", t.accountID}, WithFields(kv.Fields{
{"statusID", statusID}, {"accountTimeline", t.accountID},
}...) {"statusID", statusID},
}...)
t.Lock() t.Lock()
defer t.Unlock() defer t.Unlock()
@ -80,10 +81,11 @@ func (t *timeline) Remove(ctx context.Context, statusID string) (int, error) {
} }
func (t *timeline) RemoveAllBy(ctx context.Context, accountID string) (int, error) { func (t *timeline) RemoveAllBy(ctx context.Context, accountID string) (int, error) {
l := log.WithFields(kv.Fields{ l := log.WithContext(ctx).
{"accountTimeline", t.accountID}, WithFields(kv.Fields{
{"accountID", accountID}, {"accountTimeline", t.accountID},
}...) {"accountID", accountID},
}...)
t.Lock() t.Lock()
defer t.Unlock() defer t.Unlock()

View file

@ -48,7 +48,7 @@ func (i *importer) Import(ctx context.Context, path string) error {
err := decoder.Decode(&entry) err := decoder.Decode(&entry)
if err != nil { if err != nil {
if err == io.EOF { if err == io.EOF {
log.Infof("Import: reached end of file") log.Infof(ctx, "reached end of file")
return neatClose(file) return neatClose(file)
} }
return fmt.Errorf("Import: error decoding in readLoop: %s", err) return fmt.Errorf("Import: error decoding in readLoop: %s", err)
@ -74,7 +74,7 @@ func (i *importer) inputEntry(ctx context.Context, entry transmodel.Entry) error
if err := i.putInDB(ctx, account); err != nil { if err := i.putInDB(ctx, account); err != nil {
return fmt.Errorf("inputEntry: error adding account to database: %s", err) return fmt.Errorf("inputEntry: error adding account to database: %s", err)
} }
log.Infof("inputEntry: added account with id %s", account.ID) log.Infof(ctx, "added account with id %s", account.ID)
return nil return nil
case transmodel.TransBlock: case transmodel.TransBlock:
block, err := i.blockDecode(entry) block, err := i.blockDecode(entry)
@ -84,7 +84,7 @@ func (i *importer) inputEntry(ctx context.Context, entry transmodel.Entry) error
if err := i.putInDB(ctx, block); err != nil { if err := i.putInDB(ctx, block); err != nil {
return fmt.Errorf("inputEntry: error adding block to database: %s", err) return fmt.Errorf("inputEntry: error adding block to database: %s", err)
} }
log.Infof("inputEntry: added block with id %s", block.ID) log.Infof(ctx, "added block with id %s", block.ID)
return nil return nil
case transmodel.TransDomainBlock: case transmodel.TransDomainBlock:
block, err := i.domainBlockDecode(entry) block, err := i.domainBlockDecode(entry)
@ -94,7 +94,7 @@ func (i *importer) inputEntry(ctx context.Context, entry transmodel.Entry) error
if err := i.putInDB(ctx, block); err != nil { if err := i.putInDB(ctx, block); err != nil {
return fmt.Errorf("inputEntry: error adding domain block to database: %s", err) return fmt.Errorf("inputEntry: error adding domain block to database: %s", err)
} }
log.Infof("inputEntry: added domain block with id %s", block.ID) log.Infof(ctx, "added domain block with id %s", block.ID)
return nil return nil
case transmodel.TransFollow: case transmodel.TransFollow:
follow, err := i.followDecode(entry) follow, err := i.followDecode(entry)
@ -104,7 +104,7 @@ func (i *importer) inputEntry(ctx context.Context, entry transmodel.Entry) error
if err := i.putInDB(ctx, follow); err != nil { if err := i.putInDB(ctx, follow); err != nil {
return fmt.Errorf("inputEntry: error adding follow to database: %s", err) return fmt.Errorf("inputEntry: error adding follow to database: %s", err)
} }
log.Infof("inputEntry: added follow with id %s", follow.ID) log.Infof(ctx, "added follow with id %s", follow.ID)
return nil return nil
case transmodel.TransFollowRequest: case transmodel.TransFollowRequest:
fr, err := i.followRequestDecode(entry) fr, err := i.followRequestDecode(entry)
@ -114,7 +114,7 @@ func (i *importer) inputEntry(ctx context.Context, entry transmodel.Entry) error
if err := i.putInDB(ctx, fr); err != nil { if err := i.putInDB(ctx, fr); err != nil {
return fmt.Errorf("inputEntry: error adding follow request to database: %s", err) return fmt.Errorf("inputEntry: error adding follow request to database: %s", err)
} }
log.Infof("inputEntry: added follow request with id %s", fr.ID) log.Infof(ctx, "added follow request with id %s", fr.ID)
return nil return nil
case transmodel.TransInstance: case transmodel.TransInstance:
inst, err := i.instanceDecode(entry) inst, err := i.instanceDecode(entry)
@ -124,7 +124,7 @@ func (i *importer) inputEntry(ctx context.Context, entry transmodel.Entry) error
if err := i.putInDB(ctx, inst); err != nil { if err := i.putInDB(ctx, inst); err != nil {
return fmt.Errorf("inputEntry: error adding instance to database: %s", err) return fmt.Errorf("inputEntry: error adding instance to database: %s", err)
} }
log.Infof("inputEntry: added instance with id %s", inst.ID) log.Infof(ctx, "added instance with id %s", inst.ID)
return nil return nil
case transmodel.TransUser: case transmodel.TransUser:
user, err := i.userDecode(entry) user, err := i.userDecode(entry)
@ -134,11 +134,11 @@ func (i *importer) inputEntry(ctx context.Context, entry transmodel.Entry) error
if err := i.putInDB(ctx, user); err != nil { if err := i.putInDB(ctx, user); err != nil {
return fmt.Errorf("inputEntry: error adding user to database: %s", err) return fmt.Errorf("inputEntry: error adding user to database: %s", err)
} }
log.Infof("inputEntry: added user with id %s", user.ID) log.Infof(ctx, "added user with id %s", user.ID)
return nil return nil
} }
log.Errorf("inputEntry: didn't recognize transtype '%s', skipping it", t) log.Errorf(ctx, "didn't recognize transtype '%s', skipping it", t)
return nil return nil
} }

View file

@ -76,13 +76,13 @@ func NewController(db db.DB, federatingDB federatingdb.DB, clock pub.Clock, clie
// Transport cache has TTL=1hr freq=1min // Transport cache has TTL=1hr freq=1min
c.trspCache.SetTTL(time.Hour, false) c.trspCache.SetTTL(time.Hour, false)
if !c.trspCache.Start(time.Minute) { if !c.trspCache.Start(time.Minute) {
log.Panic("failed to start transport controller cache") log.Panic(nil, "failed to start transport controller cache")
} }
// Bad hosts cache has TTL=15min freq=1min // Bad hosts cache has TTL=15min freq=1min
c.badHosts.SetTTL(15*time.Minute, false) c.badHosts.SetTTL(15*time.Minute, false)
if !c.badHosts.Start(time.Minute) { if !c.badHosts.Start(time.Minute) {
log.Panic("failed to start transport controller cache") log.Panic(nil, "failed to start transport controller cache")
} }
return c return c

View file

@ -45,26 +45,26 @@ func (t *transport) DereferenceInstance(ctx context.Context, iri *url.URL) (*gts
// This will provide the most complete picture of an instance, and avoid unnecessary api calls. // This will provide the most complete picture of an instance, and avoid unnecessary api calls.
// //
// This will only work with Mastodon-api compatible instances: Mastodon, some Pleroma instances, GoToSocial. // This will only work with Mastodon-api compatible instances: Mastodon, some Pleroma instances, GoToSocial.
log.Debugf("trying to dereference instance %s by /api/v1/instance", iri.Host) log.Debugf(ctx, "trying to dereference instance %s by /api/v1/instance", iri.Host)
i, err = dereferenceByAPIV1Instance(ctx, t, iri) i, err = dereferenceByAPIV1Instance(ctx, t, iri)
if err == nil { if err == nil {
log.Debugf("successfully dereferenced instance using /api/v1/instance") log.Debugf(ctx, "successfully dereferenced instance using /api/v1/instance")
return i, nil return i, nil
} }
log.Debugf("couldn't dereference instance using /api/v1/instance: %s", err) log.Debugf(ctx, "couldn't dereference instance using /api/v1/instance: %s", err)
// If that doesn't work, try to dereference using /.well-known/nodeinfo. // If that doesn't work, try to dereference using /.well-known/nodeinfo.
// This will involve two API calls and return less info overall, but should be more widely compatible. // This will involve two API calls and return less info overall, but should be more widely compatible.
log.Debugf("trying to dereference instance %s by /.well-known/nodeinfo", iri.Host) log.Debugf(ctx, "trying to dereference instance %s by /.well-known/nodeinfo", iri.Host)
i, err = dereferenceByNodeInfo(ctx, t, iri) i, err = dereferenceByNodeInfo(ctx, t, iri)
if err == nil { if err == nil {
log.Debugf("successfully dereferenced instance using /.well-known/nodeinfo") log.Debugf(ctx, "successfully dereferenced instance using /.well-known/nodeinfo")
return i, nil return i, nil
} }
log.Debugf("couldn't dereference instance using /.well-known/nodeinfo: %s", err) log.Debugf(ctx, "couldn't dereference instance using /.well-known/nodeinfo: %s", err)
// we couldn't dereference the instance using any of the known methods, so just return a minimal representation // we couldn't dereference the instance using any of the known methods, so just return a minimal representation
log.Debugf("returning minimal representation of instance %s", iri.Host) log.Debugf(ctx, "returning minimal representation of instance %s", iri.Host)
id, err := id.NewRandomULID() id, err := id.NewRandomULID()
if err != nil { if err != nil {
return nil, fmt.Errorf("error creating new id for instance %s: %s", iri.Host, err) return nil, fmt.Errorf("error creating new id for instance %s: %s", iri.Host, err)

View file

@ -130,11 +130,12 @@ func (t *transport) do(r *http.Request, signer func(*http.Request) error) (*http
fastFail := IsFastfail(r.Context()) fastFail := IsFastfail(r.Context())
// Start a log entry for this request // Start a log entry for this request
l := log.WithFields(kv.Fields{ l := log.WithContext(r.Context()).
{"pubKeyID", t.pubKeyID}, WithFields(kv.Fields{
{"method", r.Method}, {"pubKeyID", t.pubKeyID},
{"url", r.URL.String()}, {"method", r.Method},
}...) {"url", r.URL.String()},
}...)
r.Header.Set("User-Agent", t.controller.userAgent) r.Header.Set("User-Agent", t.controller.userAgent)

View file

@ -82,7 +82,7 @@ func (c *converter) ASRepresentationToAccount(ctx context.Context, accountable a
// account emojis (used in bio, display name, fields) // account emojis (used in bio, display name, fields)
if emojis, err := ap.ExtractEmojis(accountable); err != nil { if emojis, err := ap.ExtractEmojis(accountable); err != nil {
log.Infof("ASRepresentationToAccount: error extracting account emojis: %s", err) log.Infof(nil, "error extracting account emojis: %s", err)
} else { } else {
acct.Emojis = emojis acct.Emojis = emojis
} }
@ -217,13 +217,13 @@ func (c *converter) extractAttachments(i ap.WithAttachment) []*gtsmodel.MediaAtt
attachmentable, ok := t.(ap.Attachmentable) attachmentable, ok := t.(ap.Attachmentable)
if !ok { if !ok {
log.Error("ap attachment was not attachmentable") log.Error(nil, "ap attachment was not attachmentable")
continue continue
} }
attachment, err := ap.ExtractAttachment(attachmentable) attachment, err := ap.ExtractAttachment(attachmentable)
if err != nil { if err != nil {
log.Errorf("error extracting attachment: %s", err) log.Errorf(nil, "error extracting attachment: %s", err)
continue continue
} }
@ -684,7 +684,7 @@ func (c *converter) ASFlagToReport(ctx context.Context, flaggable ap.Flaggable)
return nil, fmt.Errorf("ASFlagToReport: db error getting status with url %s: %w", statusURIString, err) return nil, fmt.Errorf("ASFlagToReport: db error getting status with url %s: %w", statusURIString, err)
} }
log.Warnf("ASFlagToReport: reported status %s could not be found in the db, skipping it", statusURIString) log.Warnf(nil, "reported status %s could not be found in the db, skipping it", statusURIString)
continue continue
} }
} }

View file

@ -41,13 +41,13 @@
func populateDefaultAvatars() (defaultAvatars []string) { func populateDefaultAvatars() (defaultAvatars []string) {
webAssetsAbsFilePath, err := filepath.Abs(config.GetWebAssetBaseDir()) webAssetsAbsFilePath, err := filepath.Abs(config.GetWebAssetBaseDir())
if err != nil { if err != nil {
log.Panicf("populateDefaultAvatars: error getting abs path for web assets: %s", err) log.Panicf(nil, "error getting abs path for web assets: %s", err)
} }
defaultAvatarsAbsFilePath := filepath.Join(webAssetsAbsFilePath, "default_avatars") defaultAvatarsAbsFilePath := filepath.Join(webAssetsAbsFilePath, "default_avatars")
defaultAvatarFiles, err := os.ReadDir(defaultAvatarsAbsFilePath) defaultAvatarFiles, err := os.ReadDir(defaultAvatarsAbsFilePath)
if err != nil { if err != nil {
log.Warnf("populateDefaultAvatars: error reading default avatars at %s: %s", defaultAvatarsAbsFilePath, err) log.Warnf(nil, "error reading default avatars at %s: %s", defaultAvatarsAbsFilePath, err)
return return
} }

Some files were not shown because too many files have changed in this diff Show more