Source File
record.go
Belonging Package
log/slog
// Copyright 2022 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package slogimport ()const nAttrsInline = 5// A Record holds information about a log event.// Copies of a Record share state.// Do not modify a Record after handing out a copy to it.// Call [NewRecord] to create a new Record.// Use [Record.Clone] to create a copy with no shared state.type Record struct {// The time at which the output method (Log, Info, etc.) was called.Time time.Time// The log message.Message string// The level of the event.Level Level// The program counter at the time the record was constructed, as determined// by runtime.Callers. If zero, no program counter is available.//// The only valid use for this value is as an argument to// [runtime.CallersFrames]. In particular, it must not be passed to// [runtime.FuncForPC].PC uintptr// Allocation optimization: an inline array sized to hold// the majority of log calls (based on examination of open-source// code). It holds the start of the list of Attrs.front [nAttrsInline]Attr// The number of Attrs in front.nFront int// The list of Attrs except for those in front.// Invariants:// - len(back) > 0 iff nFront == len(front)// - Unused array elements are zero. Used to detect mistakes.back []Attr}// NewRecord creates a [Record] from the given arguments.// Use [Record.AddAttrs] to add attributes to the Record.//// NewRecord is intended for logging APIs that want to support a [Handler] as// a backend.func ( time.Time, Level, string, uintptr) Record {return Record{Time: ,Message: ,Level: ,PC: ,}}// Clone returns a copy of the record with no shared state.// The original record and the clone can both be modified// without interfering with each other.func ( Record) () Record {.back = slices.Clip(.back) // prevent append from mutating shared arrayreturn}// NumAttrs returns the number of attributes in the [Record].func ( Record) () int {return .nFront + len(.back)}// Attrs calls f on each Attr in the [Record].// Iteration stops if f returns false.func ( Record) ( func(Attr) bool) {for := 0; < .nFront; ++ {if !(.front[]) {return}}for , := range .back {if !() {return}}}// AddAttrs appends the given Attrs to the [Record]'s list of Attrs.// It omits empty groups.func ( *Record) ( ...Attr) {var intfor = 0; < len() && .nFront < len(.front); ++ {:= []if .Value.isEmptyGroup() {continue}.front[.nFront] =.nFront++}// Check if a copy was modified by slicing past the end// and seeing if the Attr there is non-zero.if cap(.back) > len(.back) {:= .back[:len(.back)+1][len(.back)]if !.isEmpty() {// Don't panic; copy and muddle through..back = slices.Clip(.back).back = append(.back, String("!BUG", "AddAttrs unsafely called on copy of Record made without using Record.Clone"))}}:= countEmptyGroups([:]).back = slices.Grow(.back, len([:])-)for , := range [:] {if !.Value.isEmptyGroup() {.back = append(.back, )}}}// Add converts the args to Attrs as described in [Logger.Log],// then appends the Attrs to the [Record]'s list of Attrs.// It omits empty groups.func ( *Record) ( ...any) {var Attrfor len() > 0 {, = argsToAttr()if .Value.isEmptyGroup() {continue}if .nFront < len(.front) {.front[.nFront] =.nFront++} else {if .back == nil {.back = make([]Attr, 0, countAttrs()+1)}.back = append(.back, )}}}// countAttrs returns the number of Attrs that would be created from args.func countAttrs( []any) int {:= 0for := 0; < len(); ++ {++if , := [].(string); {++}}return}const badKey = "!BADKEY"// argsToAttr turns a prefix of the nonempty args slice into an Attr// and returns the unconsumed portion of the slice.// If args[0] is an Attr, it returns it.// If args[0] is a string, it treats the first two elements as// a key-value pair.// Otherwise, it treats args[0] as a value with a missing key.func argsToAttr( []any) (Attr, []any) {switch x := [0].(type) {case string:if len() == 1 {return String(badKey, ), nil}return Any(, [1]), [2:]case Attr:return , [1:]default:return Any(badKey, ), [1:]}}// Source describes the location of a line of source code.type Source struct {// Function is the package path-qualified function name containing the// source line. If non-empty, this string uniquely identifies a single// function in the program. This may be the empty string if not known.Function string `json:"function"`// File and Line are the file name and line number (1-based) of the source// line. These may be the empty string and zero, respectively, if not known.File string `json:"file"`Line int `json:"line"`}// group returns the non-zero fields of s as a slice of attrs.// It is similar to a LogValue method, but we don't want Source// to implement LogValuer because it would be resolved before// the ReplaceAttr function was called.func ( *Source) () Value {var []Attrif .Function != "" {= append(, String("function", .Function))}if .File != "" {= append(, String("file", .File))}if .Line != 0 {= append(, Int("line", .Line))}return GroupValue(...)}// isEmpty returns whether the Source struct is nil or only contains zero fields.func ( *Source) () bool { return == nil || * == Source{} }// Source returns a new Source for the log event using r's PC.// If the PC field is zero, meaning the Record was created without the necessary information// or the location is unavailable, then nil is returned.func ( Record) () *Source {if .PC == 0 {return nil}:= runtime.CallersFrames([]uintptr{.PC}), := .Next()return &Source{Function: .Function,File: .File,Line: .Line,}}
![]() |
The pages are generated with Golds v0.7.9-preview. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |