mirror of
https://github.com/documize/community.git
synced 2025-07-19 13:19:43 +02:00
777 lines
27 KiB
Go
777 lines
27 KiB
Go
// Go support for leveled logs, analogous to https://github.com/google/glog.
|
|
//
|
|
// Copyright 2023 Google Inc. All Rights Reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
// Package glog implements logging analogous to the Google-internal C++ INFO/ERROR/V setup.
|
|
// It provides functions that have a name matched by regex:
|
|
//
|
|
// (Info|Warning|Error|Fatal)(Context)?(Depth)?(f)?
|
|
//
|
|
// If Context is present, function takes context.Context argument. The
|
|
// context is used to pass through the Trace Context to log sinks that can make use
|
|
// of it.
|
|
// It is recommended to use the context variant of the functions over the non-context
|
|
// variants if a context is available to make sure the Trace Contexts are present
|
|
// in logs.
|
|
//
|
|
// If Depth is present, this function calls log from a different depth in the call stack.
|
|
// This enables a callee to emit logs that use the callsite information of its caller
|
|
// or any other callers in the stack. When depth == 0, the original callee's line
|
|
// information is emitted. When depth > 0, depth frames are skipped in the call stack
|
|
// and the final frame is treated like the original callee to Info.
|
|
//
|
|
// If 'f' is present, function formats according to a format specifier.
|
|
//
|
|
// This package also provides V-style logging controlled by the -v and -vmodule=file=2 flags.
|
|
//
|
|
// Basic examples:
|
|
//
|
|
// glog.Info("Prepare to repel boarders")
|
|
//
|
|
// glog.Fatalf("Initialization failed: %s", err)
|
|
//
|
|
// See the documentation for the V function for an explanation of these examples:
|
|
//
|
|
// if glog.V(2) {
|
|
// glog.Info("Starting transaction...")
|
|
// }
|
|
//
|
|
// glog.V(2).Infoln("Processed", nItems, "elements")
|
|
//
|
|
// Log output is buffered and written periodically using Flush. Programs
|
|
// should call Flush before exiting to guarantee all log output is written.
|
|
//
|
|
// By default, all log statements write to files in a temporary directory.
|
|
// This package provides several flags that modify this behavior.
|
|
// As a result, flag.Parse must be called before any logging is done.
|
|
//
|
|
// -logtostderr=false
|
|
// Logs are written to standard error instead of to files.
|
|
// -alsologtostderr=false
|
|
// Logs are written to standard error as well as to files.
|
|
// -stderrthreshold=ERROR
|
|
// Log events at or above this severity are logged to standard
|
|
// error as well as to files.
|
|
// -log_dir=""
|
|
// Log files will be written to this directory instead of the
|
|
// default temporary directory.
|
|
//
|
|
// Other flags provide aids to debugging.
|
|
//
|
|
// -log_backtrace_at=""
|
|
// A comma-separated list of file and line numbers holding a logging
|
|
// statement, such as
|
|
// -log_backtrace_at=gopherflakes.go:234
|
|
// A stack trace will be written to the Info log whenever execution
|
|
// hits one of these statements. (Unlike with -vmodule, the ".go"
|
|
// must bepresent.)
|
|
// -v=0
|
|
// Enable V-leveled logging at the specified level.
|
|
// -vmodule=""
|
|
// The syntax of the argument is a comma-separated list of pattern=N,
|
|
// where pattern is a literal file name (minus the ".go" suffix) or
|
|
// "glob" pattern and N is a V level. For instance,
|
|
// -vmodule=gopher*=3
|
|
// sets the V level to 3 in all Go files whose names begin with "gopher",
|
|
// and
|
|
// -vmodule=/path/to/glog/glog_test=1
|
|
// sets the V level to 1 in the Go file /path/to/glog/glog_test.go.
|
|
// If a glob pattern contains a slash, it is matched against the full path,
|
|
// and the file name. Otherwise, the pattern is
|
|
// matched only against the file's basename. When both -vmodule and -v
|
|
// are specified, the -vmodule values take precedence for the specified
|
|
// modules.
|
|
package glog
|
|
|
|
// This file contains the parts of the log package that are shared among all
|
|
// implementations (file, envelope, and appengine).
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
stdLog "log"
|
|
"os"
|
|
"reflect"
|
|
"runtime"
|
|
"runtime/pprof"
|
|
"strconv"
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/golang/glog/internal/logsink"
|
|
"github.com/golang/glog/internal/stackdump"
|
|
)
|
|
|
|
var timeNow = time.Now // Stubbed out for testing.
|
|
|
|
// MaxSize is the maximum size of a log file in bytes.
|
|
var MaxSize uint64 = 1024 * 1024 * 1800
|
|
|
|
// ErrNoLog is the error we return if no log file has yet been created
|
|
// for the specified log type.
|
|
var ErrNoLog = errors.New("log file not yet created")
|
|
|
|
// OutputStats tracks the number of output lines and bytes written.
|
|
type OutputStats struct {
|
|
lines int64
|
|
bytes int64
|
|
}
|
|
|
|
// Lines returns the number of lines written.
|
|
func (s *OutputStats) Lines() int64 {
|
|
return atomic.LoadInt64(&s.lines)
|
|
}
|
|
|
|
// Bytes returns the number of bytes written.
|
|
func (s *OutputStats) Bytes() int64 {
|
|
return atomic.LoadInt64(&s.bytes)
|
|
}
|
|
|
|
// Stats tracks the number of lines of output and number of bytes
|
|
// per severity level. Values must be read with atomic.LoadInt64.
|
|
var Stats struct {
|
|
Info, Warning, Error OutputStats
|
|
}
|
|
|
|
var severityStats = [...]*OutputStats{
|
|
logsink.Info: &Stats.Info,
|
|
logsink.Warning: &Stats.Warning,
|
|
logsink.Error: &Stats.Error,
|
|
logsink.Fatal: nil,
|
|
}
|
|
|
|
// Level specifies a level of verbosity for V logs. The -v flag is of type
|
|
// Level and should be modified only through the flag.Value interface.
|
|
type Level int32
|
|
|
|
var metaPool sync.Pool // Pool of *logsink.Meta.
|
|
|
|
// metaPoolGet returns a *logsink.Meta from metaPool as both an interface and a
|
|
// pointer, allocating a new one if necessary. (Returning the interface value
|
|
// directly avoids an allocation if there was an existing pointer in the pool.)
|
|
func metaPoolGet() (any, *logsink.Meta) {
|
|
if metai := metaPool.Get(); metai != nil {
|
|
return metai, metai.(*logsink.Meta)
|
|
}
|
|
meta := new(logsink.Meta)
|
|
return meta, meta
|
|
}
|
|
|
|
type stack bool
|
|
|
|
const (
|
|
noStack = stack(false)
|
|
withStack = stack(true)
|
|
)
|
|
|
|
func appendBacktrace(depth int, format string, args []any) (string, []any) {
|
|
// Capture a backtrace as a stackdump.Stack (both text and PC slice).
|
|
// Structured log sinks can extract the backtrace in whichever format they
|
|
// prefer (PCs or text), and Text sinks will include it as just another part
|
|
// of the log message.
|
|
//
|
|
// Use depth instead of depth+1 so that the backtrace always includes the
|
|
// log function itself - otherwise the reason for the trace appearing in the
|
|
// log may not be obvious to the reader.
|
|
dump := stackdump.Caller(depth)
|
|
|
|
// Add an arg and an entry in the format string for the stack dump.
|
|
//
|
|
// Copy the "args" slice to avoid a rare but serious aliasing bug
|
|
// (corrupting the caller's slice if they passed it to a non-Fatal call
|
|
// using "...").
|
|
format = format + "\n\n%v\n"
|
|
args = append(append([]any(nil), args...), dump)
|
|
|
|
return format, args
|
|
}
|
|
|
|
// logf acts as ctxlogf, but doesn't expect a context.
|
|
func logf(depth int, severity logsink.Severity, verbose bool, stack stack, format string, args ...any) {
|
|
ctxlogf(nil, depth+1, severity, verbose, stack, format, args...)
|
|
}
|
|
|
|
// ctxlogf writes a log message for a log function call (or log function wrapper)
|
|
// at the given depth in the current goroutine's stack.
|
|
func ctxlogf(ctx context.Context, depth int, severity logsink.Severity, verbose bool, stack stack, format string, args ...any) {
|
|
now := timeNow()
|
|
_, file, line, ok := runtime.Caller(depth + 1)
|
|
if !ok {
|
|
file = "???"
|
|
line = 1
|
|
}
|
|
|
|
if stack == withStack || backtraceAt(file, line) {
|
|
format, args = appendBacktrace(depth+1, format, args)
|
|
}
|
|
|
|
metai, meta := metaPoolGet()
|
|
*meta = logsink.Meta{
|
|
Context: ctx,
|
|
Time: now,
|
|
File: file,
|
|
Line: line,
|
|
Depth: depth + 1,
|
|
Severity: severity,
|
|
Verbose: verbose,
|
|
Thread: int64(pid),
|
|
}
|
|
sinkf(meta, format, args...)
|
|
// Clear pointer fields so they can be garbage collected early.
|
|
meta.Context = nil
|
|
meta.Stack = nil
|
|
metaPool.Put(metai)
|
|
}
|
|
|
|
func sinkf(meta *logsink.Meta, format string, args ...any) {
|
|
meta.Depth++
|
|
n, err := logsink.Printf(meta, format, args...)
|
|
if stats := severityStats[meta.Severity]; stats != nil {
|
|
atomic.AddInt64(&stats.lines, 1)
|
|
atomic.AddInt64(&stats.bytes, int64(n))
|
|
}
|
|
|
|
if err != nil {
|
|
logsink.Printf(meta, "glog: exiting because of error: %s", err)
|
|
sinks.file.Flush()
|
|
os.Exit(2)
|
|
}
|
|
}
|
|
|
|
// CopyStandardLogTo arranges for messages written to the Go "log" package's
|
|
// default logs to also appear in the Google logs for the named and lower
|
|
// severities. Subsequent changes to the standard log's default output location
|
|
// or format may break this behavior.
|
|
//
|
|
// Valid names are "INFO", "WARNING", "ERROR", and "FATAL". If the name is not
|
|
// recognized, CopyStandardLogTo panics.
|
|
func CopyStandardLogTo(name string) {
|
|
sev, err := logsink.ParseSeverity(name)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("log.CopyStandardLogTo(%q): %v", name, err))
|
|
}
|
|
// Set a log format that captures the user's file and line:
|
|
// d.go:23: message
|
|
stdLog.SetFlags(stdLog.Lshortfile)
|
|
stdLog.SetOutput(logBridge(sev))
|
|
}
|
|
|
|
// NewStandardLogger returns a Logger that writes to the Google logs for the
|
|
// named and lower severities.
|
|
//
|
|
// Valid names are "INFO", "WARNING", "ERROR", and "FATAL". If the name is not
|
|
// recognized, NewStandardLogger panics.
|
|
func NewStandardLogger(name string) *stdLog.Logger {
|
|
sev, err := logsink.ParseSeverity(name)
|
|
if err != nil {
|
|
panic(fmt.Sprintf("log.NewStandardLogger(%q): %v", name, err))
|
|
}
|
|
return stdLog.New(logBridge(sev), "", stdLog.Lshortfile)
|
|
}
|
|
|
|
// logBridge provides the Write method that enables CopyStandardLogTo to connect
|
|
// Go's standard logs to the logs provided by this package.
|
|
type logBridge logsink.Severity
|
|
|
|
// Write parses the standard logging line and passes its components to the
|
|
// logger for severity(lb).
|
|
func (lb logBridge) Write(b []byte) (n int, err error) {
|
|
var (
|
|
file = "???"
|
|
line = 1
|
|
text string
|
|
)
|
|
// Split "d.go:23: message" into "d.go", "23", and "message".
|
|
if parts := bytes.SplitN(b, []byte{':'}, 3); len(parts) != 3 || len(parts[0]) < 1 || len(parts[2]) < 1 {
|
|
text = fmt.Sprintf("bad log format: %s", b)
|
|
} else {
|
|
file = string(parts[0])
|
|
text = string(parts[2][1:]) // skip leading space
|
|
line, err = strconv.Atoi(string(parts[1]))
|
|
if err != nil {
|
|
text = fmt.Sprintf("bad line number: %s", b)
|
|
line = 1
|
|
}
|
|
}
|
|
|
|
// The depth below hard-codes details of how stdlog gets here. The alternative would be to walk
|
|
// up the stack looking for src/log/log.go but that seems like it would be
|
|
// unfortunately slow.
|
|
const stdLogDepth = 4
|
|
|
|
metai, meta := metaPoolGet()
|
|
*meta = logsink.Meta{
|
|
Time: timeNow(),
|
|
File: file,
|
|
Line: line,
|
|
Depth: stdLogDepth,
|
|
Severity: logsink.Severity(lb),
|
|
Thread: int64(pid),
|
|
}
|
|
|
|
format := "%s"
|
|
args := []any{text}
|
|
if backtraceAt(file, line) {
|
|
format, args = appendBacktrace(meta.Depth, format, args)
|
|
}
|
|
|
|
sinkf(meta, format, args...)
|
|
metaPool.Put(metai)
|
|
|
|
return len(b), nil
|
|
}
|
|
|
|
// defaultFormat returns a fmt.Printf format specifier that formats its
|
|
// arguments as if they were passed to fmt.Print.
|
|
func defaultFormat(args []any) string {
|
|
n := len(args)
|
|
switch n {
|
|
case 0:
|
|
return ""
|
|
case 1:
|
|
return "%v"
|
|
}
|
|
|
|
b := make([]byte, 0, n*3-1)
|
|
wasString := true // Suppress leading space.
|
|
for _, arg := range args {
|
|
isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String
|
|
if wasString || isString {
|
|
b = append(b, "%v"...)
|
|
} else {
|
|
b = append(b, " %v"...)
|
|
}
|
|
wasString = isString
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
// lnFormat returns a fmt.Printf format specifier that formats its arguments
|
|
// as if they were passed to fmt.Println.
|
|
func lnFormat(args []any) string {
|
|
if len(args) == 0 {
|
|
return "\n"
|
|
}
|
|
|
|
b := make([]byte, 0, len(args)*3)
|
|
for range args {
|
|
b = append(b, "%v "...)
|
|
}
|
|
b[len(b)-1] = '\n' // Replace the last space with a newline.
|
|
return string(b)
|
|
}
|
|
|
|
// Verbose is a boolean type that implements Infof (like Printf) etc.
|
|
// See the documentation of V for more information.
|
|
type Verbose bool
|
|
|
|
// V reports whether verbosity at the call site is at least the requested level.
|
|
// The returned value is a boolean of type Verbose, which implements Info, Infoln
|
|
// and Infof. These methods will write to the Info log if called.
|
|
// Thus, one may write either
|
|
//
|
|
// if glog.V(2) { glog.Info("log this") }
|
|
//
|
|
// or
|
|
//
|
|
// glog.V(2).Info("log this")
|
|
//
|
|
// The second form is shorter but the first is cheaper if logging is off because it does
|
|
// not evaluate its arguments.
|
|
//
|
|
// Whether an individual call to V generates a log record depends on the setting of
|
|
// the -v and --vmodule flags; both are off by default. If the level in the call to
|
|
// V is at most the value of -v, or of -vmodule for the source file containing the
|
|
// call, the V call will log.
|
|
func V(level Level) Verbose {
|
|
return VDepth(1, level)
|
|
}
|
|
|
|
// VDepth acts as V but uses depth to determine which call frame to check vmodule for.
|
|
// VDepth(0, level) is the same as V(level).
|
|
func VDepth(depth int, level Level) Verbose {
|
|
return Verbose(verboseEnabled(depth+1, level))
|
|
}
|
|
|
|
// Info is equivalent to the global Info function, guarded by the value of v.
|
|
// See the documentation of V for usage.
|
|
func (v Verbose) Info(args ...any) {
|
|
v.InfoDepth(1, args...)
|
|
}
|
|
|
|
// InfoDepth is equivalent to the global InfoDepth function, guarded by the value of v.
|
|
// See the documentation of V for usage.
|
|
func (v Verbose) InfoDepth(depth int, args ...any) {
|
|
if v {
|
|
logf(depth+1, logsink.Info, true, noStack, defaultFormat(args), args...)
|
|
}
|
|
}
|
|
|
|
// InfoDepthf is equivalent to the global InfoDepthf function, guarded by the value of v.
|
|
// See the documentation of V for usage.
|
|
func (v Verbose) InfoDepthf(depth int, format string, args ...any) {
|
|
if v {
|
|
logf(depth+1, logsink.Info, true, noStack, format, args...)
|
|
}
|
|
}
|
|
|
|
// Infoln is equivalent to the global Infoln function, guarded by the value of v.
|
|
// See the documentation of V for usage.
|
|
func (v Verbose) Infoln(args ...any) {
|
|
if v {
|
|
logf(1, logsink.Info, true, noStack, lnFormat(args), args...)
|
|
}
|
|
}
|
|
|
|
// Infof is equivalent to the global Infof function, guarded by the value of v.
|
|
// See the documentation of V for usage.
|
|
func (v Verbose) Infof(format string, args ...any) {
|
|
if v {
|
|
logf(1, logsink.Info, true, noStack, format, args...)
|
|
}
|
|
}
|
|
|
|
// InfoContext is equivalent to the global InfoContext function, guarded by the value of v.
|
|
// See the documentation of V for usage.
|
|
func (v Verbose) InfoContext(ctx context.Context, args ...any) {
|
|
v.InfoContextDepth(ctx, 1, args...)
|
|
}
|
|
|
|
// InfoContextf is equivalent to the global InfoContextf function, guarded by the value of v.
|
|
// See the documentation of V for usage.
|
|
func (v Verbose) InfoContextf(ctx context.Context, format string, args ...any) {
|
|
if v {
|
|
ctxlogf(ctx, 1, logsink.Info, true, noStack, format, args...)
|
|
}
|
|
}
|
|
|
|
// InfoContextDepth is equivalent to the global InfoContextDepth function, guarded by the value of v.
|
|
// See the documentation of V for usage.
|
|
func (v Verbose) InfoContextDepth(ctx context.Context, depth int, args ...any) {
|
|
if v {
|
|
ctxlogf(ctx, depth+1, logsink.Info, true, noStack, defaultFormat(args), args...)
|
|
}
|
|
}
|
|
|
|
// InfoContextDepthf is equivalent to the global InfoContextDepthf function, guarded by the value of v.
|
|
// See the documentation of V for usage.
|
|
func (v Verbose) InfoContextDepthf(ctx context.Context, depth int, format string, args ...any) {
|
|
if v {
|
|
ctxlogf(ctx, depth+1, logsink.Info, true, noStack, format, args...)
|
|
}
|
|
}
|
|
|
|
// Info logs to the INFO log.
|
|
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
|
|
func Info(args ...any) {
|
|
InfoDepth(1, args...)
|
|
}
|
|
|
|
// InfoDepth calls Info from a different depth in the call stack.
|
|
// This enables a callee to emit logs that use the callsite information of its caller
|
|
// or any other callers in the stack. When depth == 0, the original callee's line
|
|
// information is emitted. When depth > 0, depth frames are skipped in the call stack
|
|
// and the final frame is treated like the original callee to Info.
|
|
func InfoDepth(depth int, args ...any) {
|
|
logf(depth+1, logsink.Info, false, noStack, defaultFormat(args), args...)
|
|
}
|
|
|
|
// InfoDepthf acts as InfoDepth but with format string.
|
|
func InfoDepthf(depth int, format string, args ...any) {
|
|
logf(depth+1, logsink.Info, false, noStack, format, args...)
|
|
}
|
|
|
|
// Infoln logs to the INFO log.
|
|
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
|
func Infoln(args ...any) {
|
|
logf(1, logsink.Info, false, noStack, lnFormat(args), args...)
|
|
}
|
|
|
|
// Infof logs to the INFO log.
|
|
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
|
|
func Infof(format string, args ...any) {
|
|
logf(1, logsink.Info, false, noStack, format, args...)
|
|
}
|
|
|
|
// InfoContext is like [Info], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func InfoContext(ctx context.Context, args ...any) {
|
|
InfoContextDepth(ctx, 1, args...)
|
|
}
|
|
|
|
// InfoContextf is like [Infof], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func InfoContextf(ctx context.Context, format string, args ...any) {
|
|
ctxlogf(ctx, 1, logsink.Info, false, noStack, format, args...)
|
|
}
|
|
|
|
// InfoContextDepth is like [InfoDepth], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func InfoContextDepth(ctx context.Context, depth int, args ...any) {
|
|
ctxlogf(ctx, depth+1, logsink.Info, false, noStack, defaultFormat(args), args...)
|
|
}
|
|
|
|
// InfoContextDepthf is like [InfoDepthf], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func InfoContextDepthf(ctx context.Context, depth int, format string, args ...any) {
|
|
ctxlogf(ctx, depth+1, logsink.Info, false, noStack, format, args...)
|
|
}
|
|
|
|
// Warning logs to the WARNING and INFO logs.
|
|
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
|
|
func Warning(args ...any) {
|
|
WarningDepth(1, args...)
|
|
}
|
|
|
|
// WarningDepth acts as Warning but uses depth to determine which call frame to log.
|
|
// WarningDepth(0, "msg") is the same as Warning("msg").
|
|
func WarningDepth(depth int, args ...any) {
|
|
logf(depth+1, logsink.Warning, false, noStack, defaultFormat(args), args...)
|
|
}
|
|
|
|
// WarningDepthf acts as Warningf but uses depth to determine which call frame to log.
|
|
// WarningDepthf(0, "msg") is the same as Warningf("msg").
|
|
func WarningDepthf(depth int, format string, args ...any) {
|
|
logf(depth+1, logsink.Warning, false, noStack, format, args...)
|
|
}
|
|
|
|
// Warningln logs to the WARNING and INFO logs.
|
|
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
|
func Warningln(args ...any) {
|
|
logf(1, logsink.Warning, false, noStack, lnFormat(args), args...)
|
|
}
|
|
|
|
// Warningf logs to the WARNING and INFO logs.
|
|
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
|
|
func Warningf(format string, args ...any) {
|
|
logf(1, logsink.Warning, false, noStack, format, args...)
|
|
}
|
|
|
|
// WarningContext is like [Warning], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func WarningContext(ctx context.Context, args ...any) {
|
|
WarningContextDepth(ctx, 1, args...)
|
|
}
|
|
|
|
// WarningContextf is like [Warningf], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func WarningContextf(ctx context.Context, format string, args ...any) {
|
|
ctxlogf(ctx, 1, logsink.Warning, false, noStack, format, args...)
|
|
}
|
|
|
|
// WarningContextDepth is like [WarningDepth], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func WarningContextDepth(ctx context.Context, depth int, args ...any) {
|
|
ctxlogf(ctx, depth+1, logsink.Warning, false, noStack, defaultFormat(args), args...)
|
|
}
|
|
|
|
// WarningContextDepthf is like [WarningDepthf], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func WarningContextDepthf(ctx context.Context, depth int, format string, args ...any) {
|
|
ctxlogf(ctx, depth+1, logsink.Warning, false, noStack, format, args...)
|
|
}
|
|
|
|
// Error logs to the ERROR, WARNING, and INFO logs.
|
|
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
|
|
func Error(args ...any) {
|
|
ErrorDepth(1, args...)
|
|
}
|
|
|
|
// ErrorDepth acts as Error but uses depth to determine which call frame to log.
|
|
// ErrorDepth(0, "msg") is the same as Error("msg").
|
|
func ErrorDepth(depth int, args ...any) {
|
|
logf(depth+1, logsink.Error, false, noStack, defaultFormat(args), args...)
|
|
}
|
|
|
|
// ErrorDepthf acts as Errorf but uses depth to determine which call frame to log.
|
|
// ErrorDepthf(0, "msg") is the same as Errorf("msg").
|
|
func ErrorDepthf(depth int, format string, args ...any) {
|
|
logf(depth+1, logsink.Error, false, noStack, format, args...)
|
|
}
|
|
|
|
// Errorln logs to the ERROR, WARNING, and INFO logs.
|
|
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
|
func Errorln(args ...any) {
|
|
logf(1, logsink.Error, false, noStack, lnFormat(args), args...)
|
|
}
|
|
|
|
// Errorf logs to the ERROR, WARNING, and INFO logs.
|
|
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
|
|
func Errorf(format string, args ...any) {
|
|
logf(1, logsink.Error, false, noStack, format, args...)
|
|
}
|
|
|
|
// ErrorContext is like [Error], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func ErrorContext(ctx context.Context, args ...any) {
|
|
ErrorContextDepth(ctx, 1, args...)
|
|
}
|
|
|
|
// ErrorContextf is like [Errorf], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func ErrorContextf(ctx context.Context, format string, args ...any) {
|
|
ctxlogf(ctx, 1, logsink.Error, false, noStack, format, args...)
|
|
}
|
|
|
|
// ErrorContextDepth is like [ErrorDepth], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func ErrorContextDepth(ctx context.Context, depth int, args ...any) {
|
|
ctxlogf(ctx, depth+1, logsink.Error, false, noStack, defaultFormat(args), args...)
|
|
}
|
|
|
|
// ErrorContextDepthf is like [ErrorDepthf], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func ErrorContextDepthf(ctx context.Context, depth int, format string, args ...any) {
|
|
ctxlogf(ctx, depth+1, logsink.Error, false, noStack, format, args...)
|
|
}
|
|
|
|
func ctxfatalf(ctx context.Context, depth int, format string, args ...any) {
|
|
ctxlogf(ctx, depth+1, logsink.Fatal, false, withStack, format, args...)
|
|
sinks.file.Flush()
|
|
|
|
err := abortProcess() // Should not return.
|
|
|
|
// Failed to abort the process using signals. Dump a stack trace and exit.
|
|
Errorf("abortProcess returned unexpectedly: %v", err)
|
|
sinks.file.Flush()
|
|
pprof.Lookup("goroutine").WriteTo(os.Stderr, 1)
|
|
os.Exit(2) // Exit with the same code as the default SIGABRT handler.
|
|
}
|
|
|
|
func fatalf(depth int, format string, args ...any) {
|
|
ctxfatalf(nil, depth+1, format, args...)
|
|
}
|
|
|
|
// Fatal logs to the FATAL, ERROR, WARNING, and INFO logs,
|
|
// including a stack trace of all running goroutines, then calls os.Exit(2).
|
|
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
|
|
func Fatal(args ...any) {
|
|
FatalDepth(1, args...)
|
|
}
|
|
|
|
// FatalDepth acts as Fatal but uses depth to determine which call frame to log.
|
|
// FatalDepth(0, "msg") is the same as Fatal("msg").
|
|
func FatalDepth(depth int, args ...any) {
|
|
fatalf(depth+1, defaultFormat(args), args...)
|
|
}
|
|
|
|
// FatalDepthf acts as Fatalf but uses depth to determine which call frame to log.
|
|
// FatalDepthf(0, "msg") is the same as Fatalf("msg").
|
|
func FatalDepthf(depth int, format string, args ...any) {
|
|
fatalf(depth+1, format, args...)
|
|
}
|
|
|
|
// Fatalln logs to the FATAL, ERROR, WARNING, and INFO logs,
|
|
// including a stack trace of all running goroutines, then calls os.Exit(2).
|
|
// Arguments are handled in the manner of fmt.Println; a newline is appended if missing.
|
|
func Fatalln(args ...any) {
|
|
fatalf(1, lnFormat(args), args...)
|
|
}
|
|
|
|
// Fatalf logs to the FATAL, ERROR, WARNING, and INFO logs,
|
|
// including a stack trace of all running goroutines, then calls os.Exit(2).
|
|
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
|
|
func Fatalf(format string, args ...any) {
|
|
fatalf(1, format, args...)
|
|
}
|
|
|
|
// FatalContext is like [Fatal], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func FatalContext(ctx context.Context, args ...any) {
|
|
FatalContextDepth(ctx, 1, args...)
|
|
}
|
|
|
|
// FatalContextf is like [Fatalf], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func FatalContextf(ctx context.Context, format string, args ...any) {
|
|
ctxfatalf(ctx, 1, format, args...)
|
|
}
|
|
|
|
// FatalContextDepth is like [FatalDepth], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func FatalContextDepth(ctx context.Context, depth int, args ...any) {
|
|
ctxfatalf(ctx, depth+1, defaultFormat(args), args...)
|
|
}
|
|
|
|
// FatalContextDepthf is like [FatalDepthf], but with an extra [context.Context] parameter.
|
|
func FatalContextDepthf(ctx context.Context, depth int, format string, args ...any) {
|
|
ctxfatalf(ctx, depth+1, format, args...)
|
|
}
|
|
|
|
func ctxexitf(ctx context.Context, depth int, format string, args ...any) {
|
|
ctxlogf(ctx, depth+1, logsink.Fatal, false, noStack, format, args...)
|
|
sinks.file.Flush()
|
|
os.Exit(1)
|
|
}
|
|
|
|
func exitf(depth int, format string, args ...any) {
|
|
ctxexitf(nil, depth+1, format, args...)
|
|
}
|
|
|
|
// Exit logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
|
|
// Arguments are handled in the manner of fmt.Print; a newline is appended if missing.
|
|
func Exit(args ...any) {
|
|
ExitDepth(1, args...)
|
|
}
|
|
|
|
// ExitDepth acts as Exit but uses depth to determine which call frame to log.
|
|
// ExitDepth(0, "msg") is the same as Exit("msg").
|
|
func ExitDepth(depth int, args ...any) {
|
|
exitf(depth+1, defaultFormat(args), args...)
|
|
}
|
|
|
|
// ExitDepthf acts as Exitf but uses depth to determine which call frame to log.
|
|
// ExitDepthf(0, "msg") is the same as Exitf("msg").
|
|
func ExitDepthf(depth int, format string, args ...any) {
|
|
exitf(depth+1, format, args...)
|
|
}
|
|
|
|
// Exitln logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
|
|
func Exitln(args ...any) {
|
|
exitf(1, lnFormat(args), args...)
|
|
}
|
|
|
|
// Exitf logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1).
|
|
// Arguments are handled in the manner of fmt.Printf; a newline is appended if missing.
|
|
func Exitf(format string, args ...any) {
|
|
exitf(1, format, args...)
|
|
}
|
|
|
|
// ExitContext is like [Exit], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func ExitContext(ctx context.Context, args ...any) {
|
|
ExitContextDepth(ctx, 1, args...)
|
|
}
|
|
|
|
// ExitContextf is like [Exitf], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func ExitContextf(ctx context.Context, format string, args ...any) {
|
|
ctxexitf(ctx, 1, format, args...)
|
|
}
|
|
|
|
// ExitContextDepth is like [ExitDepth], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func ExitContextDepth(ctx context.Context, depth int, args ...any) {
|
|
ctxexitf(ctx, depth+1, defaultFormat(args), args...)
|
|
}
|
|
|
|
// ExitContextDepthf is like [ExitDepthf], but with an extra [context.Context] parameter. The
|
|
// context is used to pass the Trace Context to log sinks.
|
|
func ExitContextDepthf(ctx context.Context, depth int, format string, args ...any) {
|
|
ctxexitf(ctx, depth+1, format, args...)
|
|
}
|