mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-10-29 07:42:25 -05:00
[feature + performance] add JSON logging format (#4355)
# Description Adds JSON logging as an optional alternative log output format. In the process this moves our log formatting itself into a separate subpkg to make it more easily modular, and improves caller name getting with some calling function name caching. ## Checklist - [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md). - [x] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat. - [x] I/we have not leveraged AI to create the proposed changes. - [x] I/we have performed a self-review of added code. - [x] I/we have written code that is legible and maintainable by others. - [x] I/we have commented the added code, particularly in hard-to-understand areas. - [x] I/we have made any necessary changes to documentation. - [ ] I/we have added tests that cover new code. - [x] I/we have run tests and they pass locally with the changes. - [x] I/we have run `go fmt ./...` and `golangci-lint run`. Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4355 Co-authored-by: kim <grufwub@gmail.com> Co-committed-by: kim <grufwub@gmail.com>
This commit is contained in:
parent
96c05a90a2
commit
7af9117e0d
37 changed files with 1070 additions and 439 deletions
6
vendor/codeberg.org/gruf/go-kv/v2/field_format.go
generated
vendored
6
vendor/codeberg.org/gruf/go-kv/v2/field_format.go
generated
vendored
|
|
@ -8,8 +8,6 @@ import (
|
|||
"codeberg.org/gruf/go-kv/v2/format"
|
||||
)
|
||||
|
||||
var formatter format.Formatter
|
||||
|
||||
var argsDefault = format.DefaultArgs()
|
||||
|
||||
var argsVerbose = func() format.Args {
|
||||
|
|
@ -29,7 +27,7 @@ func (f Field) AppendFormat(buf *byteutil.Buffer, vbose bool) {
|
|||
}
|
||||
AppendQuoteString(buf, f.K)
|
||||
buf.WriteByte('=')
|
||||
buf.B = formatter.Append(buf.B, f.V, args)
|
||||
buf.B = format.Global.Append(buf.B, f.V, args)
|
||||
}
|
||||
|
||||
// Value returns the formatted value string of this Field.
|
||||
|
|
@ -41,6 +39,6 @@ func (f Field) Value(vbose bool) string {
|
|||
args = argsDefault
|
||||
}
|
||||
buf := make([]byte, 0, bufsize/2)
|
||||
buf = formatter.Append(buf, f.V, args)
|
||||
buf = format.Global.Append(buf, f.V, args)
|
||||
return byteutil.B2S(buf)
|
||||
}
|
||||
|
|
|
|||
45
vendor/codeberg.org/gruf/go-kv/v2/format/abi.go
generated
vendored
45
vendor/codeberg.org/gruf/go-kv/v2/format/abi.go
generated
vendored
|
|
@ -1,4 +1,4 @@
|
|||
//go:build go1.24 && !go1.25
|
||||
//go:build go1.24 && !go1.26
|
||||
|
||||
package format
|
||||
|
||||
|
|
@ -39,26 +39,36 @@ type abi_EmptyInterface struct {
|
|||
Data unsafe.Pointer
|
||||
}
|
||||
|
||||
// abi_NonEmptyInterface is a copy of the memory layout of abi.NonEmptyInterface{},
|
||||
// which is to say also the memory layout of any interface containing method(s).
|
||||
//
|
||||
// see: go/src/internal/abi/iface.go on 1.25+
|
||||
// see: go/src/reflect/value.go on 1.24
|
||||
type abi_NonEmptyInterface struct {
|
||||
ITab uintptr
|
||||
Data unsafe.Pointer
|
||||
}
|
||||
|
||||
// see: go/src/internal/abi/type.go Type.Kind()
|
||||
func abi_Type_Kind(t reflect.Type) uint8 {
|
||||
iface := (*reflect_nonEmptyInterface)(unsafe.Pointer(&t))
|
||||
atype := (*abi_Type)(unsafe.Pointer(iface.word))
|
||||
iface := (*abi_NonEmptyInterface)(unsafe.Pointer(&t))
|
||||
atype := (*abi_Type)(unsafe.Pointer(iface.Data))
|
||||
return atype.Kind_ & abi_KindMask
|
||||
}
|
||||
|
||||
// see: go/src/internal/abi/type.go Type.IfaceIndir()
|
||||
func abi_Type_IfaceIndir(t reflect.Type) bool {
|
||||
iface := (*reflect_nonEmptyInterface)(unsafe.Pointer(&t))
|
||||
atype := (*abi_Type)(unsafe.Pointer(iface.word))
|
||||
iface := (*abi_NonEmptyInterface)(unsafe.Pointer(&t))
|
||||
atype := (*abi_Type)(unsafe.Pointer(iface.Data))
|
||||
return atype.Kind_&abi_KindDirectIface == 0
|
||||
}
|
||||
|
||||
// pack_iface packs a new reflect.nonEmptyInterface{} using shielded itab
|
||||
// pointer and data (word) pointer, returning a pointer for caller casting.
|
||||
// pack_iface packs a new reflect.nonEmptyInterface{} using shielded
|
||||
// itab and data pointer, returning a pointer for caller casting.
|
||||
func pack_iface(itab uintptr, word unsafe.Pointer) unsafe.Pointer {
|
||||
return unsafe.Pointer(&reflect_nonEmptyInterface{
|
||||
itab: itab,
|
||||
word: word,
|
||||
return unsafe.Pointer(&abi_NonEmptyInterface{
|
||||
ITab: itab,
|
||||
Data: word,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -68,8 +78,8 @@ func pack_iface(itab uintptr, word unsafe.Pointer) unsafe.Pointer {
|
|||
// this is useful for later calls to pack_iface for known type.
|
||||
func get_iface_ITab[I any](t reflect.Type) uintptr {
|
||||
s := reflect.New(t).Elem().Interface().(I)
|
||||
i := (*reflect_nonEmptyInterface)(unsafe.Pointer(&s))
|
||||
return i.itab
|
||||
i := (*abi_NonEmptyInterface)(unsafe.Pointer(&s))
|
||||
return i.ITab
|
||||
}
|
||||
|
||||
// unpack_eface returns the .Data portion of an abi.EmptyInterface{}.
|
||||
|
|
@ -162,15 +172,6 @@ func reflect_map_elem_flags(elemType reflect.Type) reflect_flag {
|
|||
return reflect_flag(abi_Type_Kind(elemType))
|
||||
}
|
||||
|
||||
// reflect_nonEmptyInterface is a copy of the memory layout of reflect.nonEmptyInterface,
|
||||
// which is also to say the memory layout of any non-empty (i.e. w/ method) interface.
|
||||
//
|
||||
// see: go/src/reflect/value.go
|
||||
type reflect_nonEmptyInterface struct {
|
||||
itab uintptr
|
||||
word unsafe.Pointer
|
||||
}
|
||||
|
||||
// reflect_Value is a copy of the memory layout of reflect.Value{}.
|
||||
//
|
||||
// see: go/src/reflect/value.go
|
||||
|
|
@ -190,7 +191,7 @@ func init() {
|
|||
// as the reflect.nonEmptyInterface{}, which itself will be a pointer
|
||||
// to the actual abi.Type{} that this reflect.Type{} is wrapping.
|
||||
func reflect_type_data(t reflect.Type) unsafe.Pointer {
|
||||
return (*reflect_nonEmptyInterface)(unsafe.Pointer(&t)).word
|
||||
return (*abi_NonEmptyInterface)(unsafe.Pointer(&t)).Data
|
||||
}
|
||||
|
||||
// build_reflect_value manually builds a reflect.Value{} by setting the internal field members.
|
||||
|
|
|
|||
123
vendor/codeberg.org/gruf/go-kv/v2/format/format.go
generated
vendored
123
vendor/codeberg.org/gruf/go-kv/v2/format/format.go
generated
vendored
|
|
@ -8,6 +8,9 @@ import (
|
|||
"unsafe"
|
||||
)
|
||||
|
||||
// Global formatter instance.
|
||||
var Global Formatter
|
||||
|
||||
// FormatFunc defines a function capable of formatting
|
||||
// the value contained in State{}.P, based on args in
|
||||
// State{}.A, storing the result in buffer State{}.B.
|
||||
|
|
@ -48,7 +51,7 @@ const ringsz = 16
|
|||
|
||||
// ptr_ring is a ring buffer of pointers,
|
||||
// purposely stored as uintptrs as all we
|
||||
// need them for is value comparisons and
|
||||
// need them for is integer comparisons and
|
||||
// we don't want to hold-up the GC.
|
||||
type ptr_ring struct {
|
||||
p [ringsz]uintptr
|
||||
|
|
@ -296,38 +299,60 @@ func (fmt *Formatter) get(t typenode) (fn FormatFunc) {
|
|||
func (fmt *Formatter) getInterfaceType(t typenode) FormatFunc {
|
||||
if t.rtype.NumMethod() == 0 {
|
||||
return func(s *State) {
|
||||
// Unpack empty interface.
|
||||
eface := *(*any)(s.P)
|
||||
s.P = unpack_eface(eface)
|
||||
|
||||
// Get reflected type information.
|
||||
rtype := reflect.TypeOf(eface)
|
||||
if rtype == nil {
|
||||
appendNil(s)
|
||||
return
|
||||
}
|
||||
|
||||
// Check for ptr recursion.
|
||||
if s.ifaces.contains(s.P) {
|
||||
getPointerType(t)(s)
|
||||
return
|
||||
}
|
||||
|
||||
// Store value ptr.
|
||||
s.ifaces.set(s.P)
|
||||
|
||||
// Wrap in our typenode for before load.
|
||||
flags := reflect_iface_elem_flags(rtype)
|
||||
t := new_typenode(rtype, flags)
|
||||
|
||||
// Load + pass to func.
|
||||
fmt.loadOrStore(t)(s)
|
||||
}
|
||||
} else {
|
||||
return func(s *State) {
|
||||
// Unpack interface-with-method ptr.
|
||||
iface := *(*interface{ M() })(s.P)
|
||||
s.P = unpack_eface(iface)
|
||||
|
||||
// Get reflected type information.
|
||||
rtype := reflect.TypeOf(iface)
|
||||
if rtype == nil {
|
||||
appendNil(s)
|
||||
return
|
||||
}
|
||||
|
||||
// Check for ptr recursion.
|
||||
if s.ifaces.contains(s.P) {
|
||||
getPointerType(t)(s)
|
||||
return
|
||||
}
|
||||
|
||||
// Store value ptr.
|
||||
s.ifaces.set(s.P)
|
||||
|
||||
// Wrap in our typenode for before load.
|
||||
flags := reflect_iface_elem_flags(rtype)
|
||||
t := new_typenode(rtype, flags)
|
||||
|
||||
// Load + pass to func.
|
||||
fmt.loadOrStore(t)(s)
|
||||
}
|
||||
}
|
||||
|
|
@ -360,14 +385,11 @@ func getIntType(t typenode) FormatFunc {
|
|||
switch {
|
||||
case s.A.AsNumber():
|
||||
// fallthrough
|
||||
case s.A.AsQuotedText():
|
||||
s.B = strconv.AppendQuoteRune(s.B, *(*rune)(s.P))
|
||||
return
|
||||
case s.A.AsQuotedASCII():
|
||||
s.B = strconv.AppendQuoteRuneToASCII(s.B, *(*rune)(s.P))
|
||||
return
|
||||
case s.A.AsText():
|
||||
s.B = AppendEscapeRune(s.B, *(*rune)(s.P))
|
||||
case s.A.AsText() || s.A.AsQuotedText():
|
||||
s.B = strconv.AppendQuoteRune(s.B, *(*rune)(s.P))
|
||||
return
|
||||
}
|
||||
appendInt(s, int64(*(*int32)(s.P)))
|
||||
|
|
@ -388,12 +410,9 @@ func getUintType(t typenode) FormatFunc {
|
|||
switch {
|
||||
case s.A.AsNumber():
|
||||
// fallthrough
|
||||
case s.A.AsQuotedText() || s.A.AsQuotedASCII():
|
||||
case s.A.AsText() || s.A.AsQuotedText() || s.A.AsQuotedASCII():
|
||||
s.B = AppendQuoteByte(s.B, *(*byte)(s.P))
|
||||
return
|
||||
case s.A.AsText():
|
||||
s.B = AppendEscapeByte(s.B, *(*byte)(s.P))
|
||||
return
|
||||
}
|
||||
appendUint(s, uint64(*(*uint8)(s.P)))
|
||||
})
|
||||
|
|
@ -468,10 +487,17 @@ func with_typestr_ptrs(t typenode, fn FormatFunc) FormatFunc {
|
|||
if fn == nil {
|
||||
panic("nil func")
|
||||
}
|
||||
|
||||
// Check for type wrapping.
|
||||
if !t.needs_typestr() {
|
||||
return fn
|
||||
}
|
||||
|
||||
// Get type string with pointers.
|
||||
typestr := t.typestr_with_ptrs()
|
||||
|
||||
// Wrap format func to include
|
||||
// type information when needed.
|
||||
return func(s *State) {
|
||||
if s.A.WithType() {
|
||||
s.B = append(s.B, "("+typestr+")("...)
|
||||
|
|
@ -485,7 +511,7 @@ func with_typestr_ptrs(t typenode, fn FormatFunc) FormatFunc {
|
|||
|
||||
func appendString(s *State, v string) {
|
||||
switch {
|
||||
case s.A.Logfmt() || s.A.WithType():
|
||||
case s.A.WithType():
|
||||
if len(v) > SingleTermLine || !IsSafeASCII(v) {
|
||||
// Requires quoting AND escaping
|
||||
s.B = strconv.AppendQuote(s.B, v)
|
||||
|
|
@ -494,8 +520,22 @@ func appendString(s *State, v string) {
|
|||
s.B = append(s.B, '"')
|
||||
s.B = AppendEscape(s.B, v)
|
||||
s.B = append(s.B, '"')
|
||||
} else if s.A.WithType() ||
|
||||
len(v) == 0 || ContainsSpaceOrTab(v) {
|
||||
} else {
|
||||
// All else, needs quotes
|
||||
s.B = append(s.B, '"')
|
||||
s.B = append(s.B, v...)
|
||||
s.B = append(s.B, '"')
|
||||
}
|
||||
case s.A.Logfmt():
|
||||
if len(v) > SingleTermLine || !IsSafeASCII(v) {
|
||||
// Requires quoting AND escaping
|
||||
s.B = strconv.AppendQuote(s.B, v)
|
||||
} else if ContainsDoubleQuote(v) {
|
||||
// Contains double quotes, needs escaping
|
||||
s.B = append(s.B, '"')
|
||||
s.B = AppendEscape(s.B, v)
|
||||
s.B = append(s.B, '"')
|
||||
} else if len(v) == 0 || ContainsSpaceOrTab(v) {
|
||||
// Contains space / empty, needs quotes
|
||||
s.B = append(s.B, '"')
|
||||
s.B = append(s.B, v...)
|
||||
|
|
@ -515,75 +555,114 @@ func appendString(s *State, v string) {
|
|||
|
||||
func appendInt(s *State, v int64) {
|
||||
args := s.A.Int
|
||||
|
||||
// Set argument defaults.
|
||||
if args == zeroArgs.Int {
|
||||
args = defaultArgs.Int
|
||||
}
|
||||
|
||||
// Add any padding.
|
||||
if args.Pad > 0 {
|
||||
const zeros = `00000000000000000000`
|
||||
if args.Pad > len(zeros) {
|
||||
panic("cannot pad > " + zeros)
|
||||
}
|
||||
|
||||
if v == 0 {
|
||||
s.B = append(s.B, zeros[:args.Pad]...)
|
||||
return
|
||||
}
|
||||
|
||||
// Get absolute.
|
||||
abs := abs64(v)
|
||||
|
||||
// Get number of required chars.
|
||||
chars := int(v / int64(args.Base))
|
||||
if v%int64(args.Base) != 0 {
|
||||
chars++
|
||||
}
|
||||
|
||||
if abs != v {
|
||||
// If this is a negative value,
|
||||
// prepend minus ourselves and
|
||||
// set value as the absolute.
|
||||
s.B = append(s.B, '-')
|
||||
v = abs
|
||||
}
|
||||
if n := args.Pad - chars; n > 0 {
|
||||
s.B = append(s.B, zeros[:n]...)
|
||||
}
|
||||
|
||||
// Prepend required zeros.
|
||||
n := args.Pad - chars
|
||||
s.B = append(s.B, zeros[:n]...)
|
||||
}
|
||||
|
||||
// Append value as signed integer w/ args.
|
||||
s.B = strconv.AppendInt(s.B, v, args.Base)
|
||||
}
|
||||
|
||||
func appendUint(s *State, v uint64) {
|
||||
args := s.A.Int
|
||||
|
||||
// Set argument defaults.
|
||||
if args == zeroArgs.Int {
|
||||
args = defaultArgs.Int
|
||||
}
|
||||
|
||||
// Add any padding.
|
||||
if args.Pad > 0 {
|
||||
const zeros = `00000000000000000000`
|
||||
if args.Pad > len(zeros) {
|
||||
panic("cannot pad > " + zeros)
|
||||
}
|
||||
|
||||
if v == 0 {
|
||||
s.B = append(s.B, zeros[:args.Pad]...)
|
||||
return
|
||||
}
|
||||
|
||||
// Get number of required chars.
|
||||
chars := int(v / uint64(args.Base))
|
||||
if v%uint64(args.Base) != 0 {
|
||||
chars++
|
||||
}
|
||||
if n := args.Pad - chars; n > 0 {
|
||||
s.B = append(s.B, zeros[:n]...)
|
||||
}
|
||||
|
||||
// Prepend required zeros.
|
||||
n := args.Pad - chars
|
||||
s.B = append(s.B, zeros[:n]...)
|
||||
}
|
||||
|
||||
// Append value as unsigned integer w/ args.
|
||||
s.B = strconv.AppendUint(s.B, v, args.Base)
|
||||
}
|
||||
|
||||
func appendFloat(s *State, v float64, bits int) {
|
||||
args := s.A.Float
|
||||
|
||||
// Set argument defaults.
|
||||
if args == zeroArgs.Float {
|
||||
args = defaultArgs.Float
|
||||
}
|
||||
s.B = strconv.AppendFloat(s.B, float64(v), args.Fmt, args.Prec, bits)
|
||||
|
||||
// Append value as float${bit} w/ args.
|
||||
s.B = strconv.AppendFloat(s.B, float64(v),
|
||||
args.Fmt, args.Prec, bits)
|
||||
}
|
||||
|
||||
func appendComplex(s *State, r, i float64, bits int) {
|
||||
args := s.A.Complex
|
||||
|
||||
// Set argument defaults.
|
||||
if args == zeroArgs.Complex {
|
||||
args = defaultArgs.Complex
|
||||
}
|
||||
s.B = strconv.AppendFloat(s.B, float64(r), args.Real.Fmt, args.Real.Prec, bits)
|
||||
|
||||
// Append real value as float${bit} w/ args.
|
||||
s.B = strconv.AppendFloat(s.B, float64(r),
|
||||
args.Real.Fmt, args.Real.Prec, bits)
|
||||
s.B = append(s.B, '+')
|
||||
s.B = strconv.AppendFloat(s.B, float64(i), args.Imag.Fmt, args.Imag.Prec, bits)
|
||||
|
||||
// Append imag value as float${bit} w/ args.
|
||||
s.B = strconv.AppendFloat(s.B, float64(i),
|
||||
args.Imag.Fmt, args.Imag.Prec, bits)
|
||||
s.B = append(s.B, 'i')
|
||||
}
|
||||
|
||||
|
|
|
|||
8
vendor/codeberg.org/gruf/go-kv/v2/format/methods.go
generated
vendored
8
vendor/codeberg.org/gruf/go-kv/v2/format/methods.go
generated
vendored
|
|
@ -45,7 +45,7 @@ func getInterfaceStringerType(t typenode) FormatFunc {
|
|||
case true:
|
||||
return with_typestr_ptrs(t, func(s *State) {
|
||||
s.P = *(*unsafe.Pointer)(s.P)
|
||||
if s.P == nil || (*reflect_nonEmptyInterface)(s.P).word == nil {
|
||||
if s.P == nil || (*abi_NonEmptyInterface)(s.P).Data == nil {
|
||||
appendNil(s)
|
||||
return
|
||||
}
|
||||
|
|
@ -54,7 +54,7 @@ func getInterfaceStringerType(t typenode) FormatFunc {
|
|||
})
|
||||
case false:
|
||||
return with_typestr_ptrs(t, func(s *State) {
|
||||
if s.P == nil || (*reflect_nonEmptyInterface)(s.P).word == nil {
|
||||
if s.P == nil || (*abi_NonEmptyInterface)(s.P).Data == nil {
|
||||
appendNil(s)
|
||||
return
|
||||
}
|
||||
|
|
@ -102,7 +102,7 @@ func getInterfaceErrorType(t typenode) FormatFunc {
|
|||
case true:
|
||||
return with_typestr_ptrs(t, func(s *State) {
|
||||
s.P = *(*unsafe.Pointer)(s.P)
|
||||
if s.P == nil || (*reflect_nonEmptyInterface)(s.P).word == nil {
|
||||
if s.P == nil || (*abi_NonEmptyInterface)(s.P).Data == nil {
|
||||
appendNil(s)
|
||||
return
|
||||
}
|
||||
|
|
@ -111,7 +111,7 @@ func getInterfaceErrorType(t typenode) FormatFunc {
|
|||
})
|
||||
case false:
|
||||
return with_typestr_ptrs(t, func(s *State) {
|
||||
if s.P == nil || (*reflect_nonEmptyInterface)(s.P).word == nil {
|
||||
if s.P == nil || (*abi_NonEmptyInterface)(s.P).Data == nil {
|
||||
appendNil(s)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
6
vendor/codeberg.org/gruf/go-kv/v2/util.go
generated
vendored
6
vendor/codeberg.org/gruf/go-kv/v2/util.go
generated
vendored
|
|
@ -17,8 +17,8 @@ func AppendQuoteString(buf *byteutil.Buffer, str string) {
|
|||
return
|
||||
|
||||
case len(str) == 1:
|
||||
// Append escaped single byte.
|
||||
buf.B = format.AppendEscapeByte(buf.B, str[0])
|
||||
// Append quoted escaped single byte.
|
||||
buf.B = format.AppendQuoteByte(buf.B, str[0])
|
||||
return
|
||||
|
||||
case len(str) > format.SingleTermLine || !format.IsSafeASCII(str):
|
||||
|
|
@ -62,7 +62,7 @@ func AppendQuoteValue(buf *byteutil.Buffer, str string) {
|
|||
return
|
||||
|
||||
case len(str) == 1:
|
||||
// Append quoted single byte.
|
||||
// Append quoted escaped single byte.
|
||||
buf.B = format.AppendQuoteByte(buf.B, str[0])
|
||||
return
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue