[chore] improved federatingdb logging in cases of unknown iri / types (#3313)

* improved federatingdb logging in cases of unknown iri / types, add new log methods

* whoops; forgot to wrap log argument in serialize{} !

* use debug instead of warn level

* switch last entry to Debug
This commit is contained in:
kim 2024-09-17 19:35:47 +00:00 committed by GitHub
parent e337aa83b8
commit 8effc77788
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 146 additions and 135 deletions

View File

@ -22,7 +22,6 @@ import (
"errors" "errors"
"net/url" "net/url"
"codeberg.org/gruf/go-logger/v2/level"
"github.com/superseriousbusiness/activity/streams/vocab" "github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/ap" "github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/db"
@ -46,15 +45,7 @@ func (f *federatingDB) GetAccept(
} }
func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsAccept) error { func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsAccept) error {
if log.Level() >= level.DEBUG { log.DebugKV(ctx, "accept", serialize{accept})
i, err := marshalItem(accept)
if err != nil {
return err
}
l := log.WithContext(ctx).
WithField("accept", i)
l.Debug("entering Accept")
}
activityContext := getActivityContext(ctx) activityContext := getActivityContext(ctx)
if activityContext.internal { if activityContext.internal {
@ -81,10 +72,9 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA
// handling the ones we know how to handle. // handling the ones we know how to handle.
for _, object := range ap.ExtractObjects(accept) { for _, object := range ap.ExtractObjects(accept) {
if asType := object.GetType(); asType != nil { if asType := object.GetType(); asType != nil {
// Check and handle any
// vocab.Type objects. // Check and handle any vocab.Type objects.
// nolint:gocritic switch name := asType.GetTypeName(); name {
switch asType.GetTypeName() {
// ACCEPT FOLLOW // ACCEPT FOLLOW
case ap.ActivityFollow: case ap.ActivityFollow:
@ -96,6 +86,10 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA
); err != nil { ); err != nil {
return err return err
} }
// UNHANDLED
default:
log.Debugf(ctx, "unhandled object type: %s", name)
} }
} else if object.IsIRI() { } else if object.IsIRI() {
@ -137,6 +131,10 @@ func (f *federatingDB) Accept(ctx context.Context, accept vocab.ActivityStreamsA
); err != nil { ); err != nil {
return err return err
} }
// UNHANDLED
default:
log.Debugf(ctx, "unhandled iri type: %s", objIRI)
} }
} }
} }

View File

@ -22,7 +22,6 @@ import (
"net/url" "net/url"
"slices" "slices"
"codeberg.org/gruf/go-logger/v2/level"
"github.com/superseriousbusiness/activity/streams/vocab" "github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/ap" "github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/gtserror"
@ -31,15 +30,7 @@ import (
) )
func (f *federatingDB) Announce(ctx context.Context, announce vocab.ActivityStreamsAnnounce) error { func (f *federatingDB) Announce(ctx context.Context, announce vocab.ActivityStreamsAnnounce) error {
if log.Level() >= level.DEBUG { log.DebugKV(ctx, "announce", serialize{announce})
i, err := marshalItem(announce)
if err != nil {
return err
}
l := log.WithContext(ctx).
WithField("announce", i)
l.Debug("entering Announce")
}
activityContext := getActivityContext(ctx) activityContext := getActivityContext(ctx)
if activityContext.internal { if activityContext.internal {

View File

@ -22,7 +22,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"codeberg.org/gruf/go-logger/v2/level"
"github.com/miekg/dns" "github.com/miekg/dns"
"github.com/superseriousbusiness/activity/streams/vocab" "github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/ap" "github.com/superseriousbusiness/gotosocial/internal/ap"
@ -48,17 +47,7 @@ import (
// Under certain conditions and network activities, Create may be called // Under certain conditions and network activities, Create may be called
// multiple times for the same ActivityStreams object. // multiple times for the same ActivityStreams object.
func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error { func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {
if log.Level() >= level.TRACE { log.DebugKV(ctx, "create", serialize{asType})
i, err := marshalItem(asType)
if err != nil {
return err
}
log.
WithContext(ctx).
WithField("create", i).
Trace("entering Create")
}
activityContext := getActivityContext(ctx) activityContext := getActivityContext(ctx)
if activityContext.internal { if activityContext.internal {
@ -74,7 +63,7 @@ func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {
return nil return nil
} }
switch asType.GetTypeName() { switch name := asType.GetTypeName(); name {
case ap.ActivityBlock: case ap.ActivityBlock:
// BLOCK SOMETHING // BLOCK SOMETHING
return f.activityBlock(ctx, asType, receivingAcct, requestingAcct) return f.activityBlock(ctx, asType, receivingAcct, requestingAcct)
@ -90,6 +79,8 @@ func (f *federatingDB) Create(ctx context.Context, asType vocab.Type) error {
case ap.ActivityFlag: case ap.ActivityFlag:
// FLAG / REPORT SOMETHING // FLAG / REPORT SOMETHING
return f.activityFlag(ctx, asType, receivingAcct, requestingAcct) return f.activityFlag(ctx, asType, receivingAcct, requestingAcct)
default:
log.Debugf(ctx, "unhandled object type: %s", name)
} }
return nil return nil

View File

@ -37,6 +37,8 @@ import (
// //
// 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 {
log.DebugKV(ctx, "id", id)
activityContext := getActivityContext(ctx) activityContext := getActivityContext(ctx)
if activityContext.internal { if activityContext.internal {
return nil // Already processed. return nil // Already processed.
@ -81,9 +83,7 @@ func (f *federatingDB) Delete(ctx context.Context, id *url.URL) error {
return nil return nil
} }
// Log at debug level, as lots of these could indicate federation log.Debugf(ctx, "unknown iri: %s", uriStr)
// issues between remote and this instance, or help with debugging.
log.Debugf(ctx, "received delete for unknown target: %s", uriStr)
return nil return nil
} }

View File

@ -20,9 +20,6 @@ package federatingdb
import ( import (
"context" "context"
"net/url" "net/url"
"codeberg.org/gruf/go-kv"
"github.com/superseriousbusiness/gotosocial/internal/log"
) )
// Exists returns true if the database has an entry for the specified // Exists returns true if the database has an entry for the specified
@ -32,10 +29,5 @@ import (
// //
// 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(ctx 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.WithContext(ctx).
WithFields(kv.Fields{
{"id", id},
}...)
l.Debug("entering Exists")
return false, nil return false, nil
} }

View File

@ -22,7 +22,6 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"codeberg.org/gruf/go-kv"
"github.com/superseriousbusiness/activity/streams/vocab" "github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/log" "github.com/superseriousbusiness/gotosocial/internal/log"
"github.com/superseriousbusiness/gotosocial/internal/uris" "github.com/superseriousbusiness/gotosocial/internal/uris"
@ -32,9 +31,7 @@ import (
// //
// 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.WithContext(ctx). log.DebugKV(ctx, "id", id)
WithFields(kv.Fields{{"id", id}}...)
l.Debug("entering Get")
switch { switch {

View File

@ -27,7 +27,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"codeberg.org/gruf/go-logger/v2/level"
"github.com/superseriousbusiness/activity/streams/vocab" "github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/ap" "github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/gtserror" "github.com/superseriousbusiness/gotosocial/internal/gtserror"
@ -37,15 +36,7 @@ import (
) )
func (f *federatingDB) Move(ctx context.Context, move vocab.ActivityStreamsMove) error { func (f *federatingDB) Move(ctx context.Context, move vocab.ActivityStreamsMove) error {
if log.Level() >= level.DEBUG { log.DebugKV(ctx, "move", serialize{move})
i, err := marshalItem(move)
if err != nil {
return err
}
l := log.WithContext(ctx).
WithField("move", i)
l.Debug("entering Move")
}
activityContext := getActivityContext(ctx) activityContext := getActivityContext(ctx)
if activityContext.internal { if activityContext.internal {

View File

@ -23,7 +23,6 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"codeberg.org/gruf/go-kv"
"github.com/superseriousbusiness/gotosocial/internal/config" "github.com/superseriousbusiness/gotosocial/internal/config"
"github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/db"
"github.com/superseriousbusiness/gotosocial/internal/gtscontext" "github.com/superseriousbusiness/gotosocial/internal/gtscontext"
@ -36,15 +35,11 @@ import (
// 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.WithContext(ctx). log.DebugKV(ctx, "id", id)
WithFields(kv.Fields{
{"id", id},
}...)
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
if host := config.GetHost(); id.Host != host { if host := config.GetHost(); id.Host != host {
l.Tracef("we DO NOT own activity because the host is %s not %s", id.Host, host) log.Tracef(ctx, "we DO NOT own activity because the host is %s not %s", id.Host, host)
return false, nil return false, nil
} }
@ -85,7 +80,7 @@ func (f *federatingDB) Owns(ctx context.Context, id *url.URL) (bool, error) {
// an actual error happened // an actual error happened
return false, fmt.Errorf("database error fetching account with username %s: %s", username, err) return false, fmt.Errorf("database error fetching account with username %s: %s", username, err)
} }
l.Debugf("we own url %s", id.String()) log.Debugf(ctx, "we own url %s", id)
return true, nil return true, nil
} }
@ -102,7 +97,7 @@ func (f *federatingDB) Owns(ctx context.Context, id *url.URL) (bool, error) {
// an actual error happened // an actual error happened
return false, fmt.Errorf("database error fetching account with username %s: %s", username, err) return false, fmt.Errorf("database error fetching account with username %s: %s", username, err)
} }
l.Debugf("we own url %s", id.String()) log.Debugf(ctx, "we own url %s", id)
return true, nil return true, nil
} }
@ -119,7 +114,7 @@ func (f *federatingDB) Owns(ctx context.Context, id *url.URL) (bool, error) {
// an actual error happened // an actual error happened
return false, fmt.Errorf("database error fetching account with username %s: %s", username, err) return false, fmt.Errorf("database error fetching account with username %s: %s", username, err)
} }
l.Debugf("we own url %s", id.String()) log.Debugf(ctx, "we own url %s", id)
return true, nil return true, nil
} }
@ -148,7 +143,7 @@ func (f *federatingDB) Owns(ctx context.Context, id *url.URL) (bool, error) {
// an actual error happened // an actual error happened
return false, fmt.Errorf("database error fetching block with id %s: %s", blockID, err) return false, fmt.Errorf("database error fetching block with id %s: %s", blockID, err)
} }
l.Debugf("we own url %s", id.String()) log.Debugf(ctx, "we own url %s", id)
return true, nil return true, nil
} }

View File

@ -22,7 +22,6 @@ import (
"errors" "errors"
"time" "time"
"codeberg.org/gruf/go-logger/v2/level"
"github.com/superseriousbusiness/activity/streams/vocab" "github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/ap" "github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/db"
@ -35,15 +34,7 @@ import (
) )
func (f *federatingDB) Reject(ctx context.Context, reject vocab.ActivityStreamsReject) error { func (f *federatingDB) Reject(ctx context.Context, reject vocab.ActivityStreamsReject) error {
if log.Level() >= level.DEBUG { log.DebugKV(ctx, "reject", serialize{reject})
i, err := marshalItem(reject)
if err != nil {
return err
}
l := log.WithContext(ctx).
WithField("reject", i)
l.Debug("entering Reject")
}
activityContext := getActivityContext(ctx) activityContext := getActivityContext(ctx)
if activityContext.internal { if activityContext.internal {
@ -62,10 +53,8 @@ func (f *federatingDB) Reject(ctx context.Context, reject vocab.ActivityStreamsR
for _, object := range ap.ExtractObjects(reject) { for _, object := range ap.ExtractObjects(reject) {
if asType := object.GetType(); asType != nil { if asType := object.GetType(); asType != nil {
// Check and handle any // Check and handle any vocab.Type objects.
// vocab.Type objects. switch name := asType.GetTypeName(); name {
// nolint:gocritic
switch asType.GetTypeName() {
// REJECT FOLLOW // REJECT FOLLOW
case ap.ActivityFollow: case ap.ActivityFollow:
@ -77,6 +66,10 @@ func (f *federatingDB) Reject(ctx context.Context, reject vocab.ActivityStreamsR
); err != nil { ); err != nil {
return err return err
} }
// UNHANDLED
default:
log.Debugf(ctx, "unhandled object type: %s", name)
} }
} else if object.IsIRI() { } else if object.IsIRI() {
@ -118,6 +111,10 @@ func (f *federatingDB) Reject(ctx context.Context, reject vocab.ActivityStreamsR
); err != nil { ); err != nil {
return err return err
} }
// UNHANDLED
default:
log.Debugf(ctx, "unhandled iri type: %s", objIRI)
} }
} }
} }

View File

@ -22,7 +22,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"codeberg.org/gruf/go-logger/v2/level"
"github.com/superseriousbusiness/activity/streams/vocab" "github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/ap" "github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/db"
@ -33,15 +32,7 @@ import (
) )
func (f *federatingDB) Undo(ctx context.Context, undo vocab.ActivityStreamsUndo) error { func (f *federatingDB) Undo(ctx context.Context, undo vocab.ActivityStreamsUndo) error {
if log.Level() >= level.DEBUG { log.DebugKV(ctx, "undo", serialize{undo})
i, err := marshalItem(undo)
if err != nil {
return err
}
l := log.WithContext(ctx).
WithField("undo", i)
l.Debug("entering Undo")
}
activityContext := getActivityContext(ctx) activityContext := getActivityContext(ctx)
if activityContext.internal { if activityContext.internal {
@ -59,9 +50,8 @@ func (f *federatingDB) Undo(ctx context.Context, undo vocab.ActivityStreamsUndo)
continue continue
} }
// Check and handle any // Check and handle any vocab.Type objects.
// vocab.Type objects. switch name := asType.GetTypeName(); name {
switch asType.GetTypeName() {
// UNDO FOLLOW // UNDO FOLLOW
case ap.ActivityFollow: case ap.ActivityFollow:
@ -99,10 +89,9 @@ func (f *federatingDB) Undo(ctx context.Context, undo vocab.ActivityStreamsUndo)
return err return err
} }
// UNDO ANNOUNCE // UNHANDLED
case ap.ActivityAnnounce: default:
// TODO: actually handle this! log.Debugf(ctx, "unhandled object type: %s", name)
log.Warn(ctx, "skipped undo announce")
} }
} }

View File

@ -21,7 +21,6 @@ import (
"context" "context"
"errors" "errors"
"codeberg.org/gruf/go-logger/v2/level"
"github.com/superseriousbusiness/activity/streams/vocab" "github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/ap" "github.com/superseriousbusiness/gotosocial/internal/ap"
"github.com/superseriousbusiness/gotosocial/internal/config" "github.com/superseriousbusiness/gotosocial/internal/config"
@ -42,16 +41,7 @@ import (
// //
// 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) Update(ctx context.Context, asType vocab.Type) error { func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {
l := log.WithContext(ctx) log.DebugKV(ctx, "update", serialize{asType})
if log.Level() >= level.DEBUG {
i, err := marshalItem(asType)
if err != nil {
return err
}
l = l.WithField("update", i)
l.Debug("entering Update")
}
activityContext := getActivityContext(ctx) activityContext := getActivityContext(ctx)
if activityContext.internal { if activityContext.internal {
@ -69,6 +59,7 @@ func (f *federatingDB) Update(ctx context.Context, asType vocab.Type) error {
return f.updateStatusable(ctx, receivingAcct, requestingAcct, statusable) return f.updateStatusable(ctx, receivingAcct, requestingAcct, statusable)
} }
log.Debugf(ctx, "unhandled object type: %T", asType)
return nil return nil
} }

View File

@ -23,7 +23,7 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"codeberg.org/gruf/go-logger/v2/level" "codeberg.org/gruf/go-byteutil"
"github.com/superseriousbusiness/activity/streams" "github.com/superseriousbusiness/activity/streams"
"github.com/superseriousbusiness/activity/streams/vocab" "github.com/superseriousbusiness/activity/streams/vocab"
"github.com/superseriousbusiness/gotosocial/internal/ap" "github.com/superseriousbusiness/gotosocial/internal/ap"
@ -91,15 +91,7 @@ func sameActor(actor1 vocab.ActivityStreamsActorProperty, actor2 vocab.ActivityS
// The go-fed library will handle setting the 'id' property on the // The go-fed library will handle setting the 'id' property on the
// activity or object provided with the value returned. // activity or object provided with the value returned.
func (f *federatingDB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL, err error) { func (f *federatingDB) NewID(ctx context.Context, t vocab.Type) (idURL *url.URL, err error) {
if log.Level() >= level.DEBUG { log.DebugKV(ctx, "newID", serialize{t})
i, err := marshalItem(t)
if err != nil {
return nil, err
}
l := log.WithContext(ctx).
WithField("newID", i)
l.Debug("entering NewID")
}
// Most of our types set an ID already // Most of our types set an ID already
// by this point, return this if found. // by this point, return this if found.
@ -268,16 +260,20 @@ func getActivityContext(ctx context.Context) activityContext {
} }
} }
func marshalItem(item vocab.Type) (string, error) { // serialize wraps a vocab.Type to provide
m, err := ap.Serialize(item) // lazy-serialization along with error output.
type serialize struct{ item vocab.Type }
func (s serialize) String() string {
m, err := ap.Serialize(s.item)
if err != nil { if err != nil {
return "", err return "!(error serializing item: " + err.Error() + ")"
} }
b, err := json.Marshal(m) b, err := json.Marshal(m)
if err != nil { if err != nil {
return "", err return "!(error json marshaling item: " + err.Error() + ")"
} }
return string(b), nil return byteutil.B2S(b)
} }

View File

@ -22,6 +22,7 @@ import (
"fmt" "fmt"
"log/syslog" "log/syslog"
"os" "os"
"slices"
"strings" "strings"
"syscall" "syscall"
"time" "time"
@ -102,6 +103,14 @@ func Tracef(ctx context.Context, s string, a ...interface{}) {
logf(ctx, 3, level.TRACE, nil, s, a...) logf(ctx, 3, level.TRACE, nil, s, a...)
} }
func TraceKV(ctx context.Context, key string, value interface{}) {
logf(ctx, 3, level.TRACE, []kv.Field{{K: key, V: value}}, "")
}
func TraceKVs(ctx context.Context, kvs ...kv.Field) {
logf(ctx, 3, level.TRACE, kvs, "")
}
func Debug(ctx context.Context, a ...interface{}) { func Debug(ctx context.Context, a ...interface{}) {
logf(ctx, 3, level.DEBUG, nil, args(len(a)), a...) logf(ctx, 3, level.DEBUG, nil, args(len(a)), a...)
} }
@ -110,6 +119,14 @@ func Debugf(ctx context.Context, s string, a ...interface{}) {
logf(ctx, 3, level.DEBUG, nil, s, a...) logf(ctx, 3, level.DEBUG, nil, s, a...)
} }
func DebugKV(ctx context.Context, key string, value interface{}) {
logf(ctx, 3, level.DEBUG, []kv.Field{{K: key, V: value}}, "")
}
func DebugKVs(ctx context.Context, kvs ...kv.Field) {
logf(ctx, 3, level.DEBUG, kvs, "")
}
func Info(ctx context.Context, a ...interface{}) { func Info(ctx context.Context, a ...interface{}) {
logf(ctx, 3, level.INFO, nil, args(len(a)), a...) logf(ctx, 3, level.INFO, nil, args(len(a)), a...)
} }
@ -118,6 +135,14 @@ func Infof(ctx context.Context, s string, a ...interface{}) {
logf(ctx, 3, level.INFO, nil, s, a...) logf(ctx, 3, level.INFO, nil, s, a...)
} }
func InfoKV(ctx context.Context, key string, value interface{}) {
logf(ctx, 3, level.INFO, []kv.Field{{K: key, V: value}}, "")
}
func InfoKVs(ctx context.Context, kvs ...kv.Field) {
logf(ctx, 3, level.INFO, kvs, "")
}
func Warn(ctx context.Context, a ...interface{}) { func Warn(ctx context.Context, a ...interface{}) {
logf(ctx, 3, level.WARN, nil, args(len(a)), a...) logf(ctx, 3, level.WARN, nil, args(len(a)), a...)
} }
@ -126,6 +151,14 @@ func Warnf(ctx context.Context, s string, a ...interface{}) {
logf(ctx, 3, level.WARN, nil, s, a...) logf(ctx, 3, level.WARN, nil, s, a...)
} }
func WarnKV(ctx context.Context, key string, value interface{}) {
logf(ctx, 3, level.WARN, []kv.Field{{K: key, V: value}}, "")
}
func WarnKVs(ctx context.Context, kvs ...kv.Field) {
logf(ctx, 3, level.WARN, kvs, "")
}
func Error(ctx context.Context, a ...interface{}) { func Error(ctx context.Context, a ...interface{}) {
logf(ctx, 3, level.ERROR, nil, args(len(a)), a...) logf(ctx, 3, level.ERROR, nil, args(len(a)), a...)
} }
@ -134,6 +167,14 @@ func Errorf(ctx context.Context, s string, a ...interface{}) {
logf(ctx, 3, level.ERROR, nil, s, a...) logf(ctx, 3, level.ERROR, nil, s, a...)
} }
func ErrorKV(ctx context.Context, key string, value interface{}) {
logf(ctx, 3, level.ERROR, []kv.Field{{K: key, V: value}}, "")
}
func ErrorKVs(ctx context.Context, kvs ...kv.Field) {
logf(ctx, 3, level.WARN, kvs, "")
}
func Fatal(ctx context.Context, a ...interface{}) { func Fatal(ctx context.Context, a ...interface{}) {
defer syscall.Exit(1) defer syscall.Exit(1)
logf(ctx, 3, level.FATAL, nil, args(len(a)), a...) logf(ctx, 3, level.FATAL, nil, args(len(a)), a...)
@ -144,6 +185,14 @@ func Fatalf(ctx context.Context, s string, a ...interface{}) {
logf(ctx, 3, level.FATAL, nil, s, a...) logf(ctx, 3, level.FATAL, nil, s, a...)
} }
func FatalKV(ctx context.Context, key string, value interface{}) {
logf(ctx, 3, level.FATAL, []kv.Field{{K: key, V: value}}, "")
}
func FatalKVs(ctx context.Context, kvs ...kv.Field) {
logf(ctx, 3, level.FATAL, kvs, "")
}
func Panic(ctx context.Context, a ...interface{}) { func Panic(ctx context.Context, a ...interface{}) {
defer panic(fmt.Sprint(a...)) defer panic(fmt.Sprint(a...))
logf(ctx, 3, level.PANIC, nil, args(len(a)), a...) logf(ctx, 3, level.PANIC, nil, args(len(a)), a...)
@ -154,6 +203,14 @@ func Panicf(ctx context.Context, s string, a ...interface{}) {
logf(ctx, 3, level.PANIC, nil, s, a...) logf(ctx, 3, level.PANIC, nil, s, a...)
} }
func PanicKV(ctx context.Context, key string, value interface{}) {
logf(ctx, 3, level.PANIC, []kv.Field{{K: key, V: value}}, "")
}
func PanicKVs(ctx context.Context, kvs ...kv.Field) {
logf(ctx, 3, level.PANIC, kvs, "")
}
// 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(ctx context.Context, lvl level.LEVEL, a ...interface{}) { func Log(ctx context.Context, lvl level.LEVEL, a ...interface{}) {
logf(ctx, 3, lvl, nil, args(len(a)), a...) logf(ctx, 3, lvl, nil, args(len(a)), a...)
@ -164,16 +221,36 @@ func Logf(ctx context.Context, lvl level.LEVEL, s string, a ...interface{}) {
logf(ctx, 3, lvl, nil, s, a...) logf(ctx, 3, lvl, nil, s, a...)
} }
// LogKV will log the one key-value field to the log at given level.
func LogKV(ctx context.Context, lvl level.LEVEL, key string, value interface{}) { //nolint:revive
logf(ctx, 3, level.DEBUG, []kv.Field{{K: key, V: value}}, "")
}
// LogKVs will log key-value fields to the log at given level.
func LogKVs(ctx context.Context, lvl level.LEVEL, kvs ...kv.Field) { //nolint:revive
logf(ctx, 3, lvl, kvs, "")
}
// Print will log formatted args to the stdout log output. // Print will log formatted args to the stdout log output.
func Print(a ...interface{}) { func Print(a ...interface{}) {
printf(3, nil, args(len(a)), a...) printf(3, nil, args(len(a)), a...)
} }
// Print will log format string to the stdout log output. // Printf will log format string to the stdout log output.
func Printf(s string, a ...interface{}) { func Printf(s string, a ...interface{}) {
printf(3, nil, s, a...) printf(3, nil, s, a...)
} }
// PrintKVs will log the one key-value field to the stdout log output.
func PrintKV(key string, value interface{}) {
printf(3, []kv.Field{{K: key, V: value}}, "")
}
// PrintKVs will log key-value fields to the stdout log output.
func PrintKVs(kvs ...kv.Field) {
printf(3, kvs, "")
}
func printf(depth int, fields []kv.Field, s string, a ...interface{}) { func printf(depth int, fields []kv.Field, s string, a ...interface{}) {
// Acquire buffer // Acquire buffer
buf := getBuf() buf := getBuf()
@ -249,10 +326,16 @@ func logf(ctx context.Context, depth int, lvl level.LEVEL, fields []kv.Field, s
} }
} }
// Append formatted fields with msg if s != "" {
kv.Fields(append(fields, kv.Field{ // Append message to log fields.
fields = slices.Grow(fields, 1)
fields = append(fields, kv.Field{
K: "msg", V: fmt.Sprintf(s, a...), K: "msg", V: fmt.Sprintf(s, a...),
})).AppendFormat(buf, false) })
}
// Append formatted fields to log buffer.
kv.Fields(fields).AppendFormat(buf, false)
if buf.B[len(buf.B)-1] != '\n' { if buf.B[len(buf.B)-1] != '\n' {
// Append a final newline // Append a final newline