1 // Go support for leveled logs, analogous to https://github.com/google/glog. 2 // 3 // Copyright 2023 Google Inc. All Rights Reserved. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 // Package glog implements logging analogous to the Google-internal C++ INFO/ERROR/V setup. 18 // It provides functions that have a name matched by regex: 19 // 20 // (Info|Warning|Error|Fatal)(Context)?(Depth)?(f)? 21 // 22 // If Context is present, function takes context.Context argument. The 23 // context is used to pass through the Trace Context to log sinks that can make use 24 // of it. 25 // It is recommended to use the context variant of the functions over the non-context 26 // variants if a context is available to make sure the Trace Contexts are present 27 // in logs. 28 // 29 // If Depth is present, this function calls log from a different depth in the call stack. 30 // This enables a callee to emit logs that use the callsite information of its caller 31 // or any other callers in the stack. When depth == 0, the original callee's line 32 // information is emitted. When depth > 0, depth frames are skipped in the call stack 33 // and the final frame is treated like the original callee to Info. 34 // 35 // If 'f' is present, function formats according to a format specifier. 36 // 37 // This package also provides V-style logging controlled by the -v and -vmodule=file=2 flags. 38 // 39 // Basic examples: 40 // 41 // glog.Info("Prepare to repel boarders") 42 // 43 // glog.Fatalf("Initialization failed: %s", err) 44 // 45 // See the documentation for the V function for an explanation of these examples: 46 // 47 // if glog.V(2) { 48 // glog.Info("Starting transaction...") 49 // } 50 // 51 // glog.V(2).Infoln("Processed", nItems, "elements") 52 // 53 // Log output is buffered and written periodically using Flush. Programs 54 // should call Flush before exiting to guarantee all log output is written. 55 // 56 // By default, all log statements write to files in a temporary directory. 57 // This package provides several flags that modify this behavior. 58 // As a result, flag.Parse must be called before any logging is done. 59 // 60 // -logtostderr=false 61 // Logs are written to standard error instead of to files. 62 // -alsologtostderr=false 63 // Logs are written to standard error as well as to files. 64 // -stderrthreshold=ERROR 65 // Log events at or above this severity are logged to standard 66 // error as well as to files. 67 // -log_dir="" 68 // Log files will be written to this directory instead of the 69 // default temporary directory. 70 // 71 // Other flags provide aids to debugging. 72 // 73 // -log_backtrace_at="" 74 // A comma-separated list of file and line numbers holding a logging 75 // statement, such as 76 // -log_backtrace_at=gopherflakes.go:234 77 // A stack trace will be written to the Info log whenever execution 78 // hits one of these statements. (Unlike with -vmodule, the ".go" 79 // must bepresent.) 80 // -v=0 81 // Enable V-leveled logging at the specified level. 82 // -vmodule="" 83 // The syntax of the argument is a comma-separated list of pattern=N, 84 // where pattern is a literal file name (minus the ".go" suffix) or 85 // "glob" pattern and N is a V level. For instance, 86 // -vmodule=gopher*=3 87 // sets the V level to 3 in all Go files whose names begin with "gopher", 88 // and 89 // -vmodule=/path/to/glog/glog_test=1 90 // sets the V level to 1 in the Go file /path/to/glog/glog_test.go. 91 // If a glob pattern contains a slash, it is matched against the full path, 92 // and the file name. Otherwise, the pattern is 93 // matched only against the file's basename. When both -vmodule and -v 94 // are specified, the -vmodule values take precedence for the specified 95 // modules. 96 package glog 97 98 // This file contains the parts of the log package that are shared among all 99 // implementations (file, envelope, and appengine). 100 101 import ( 102 "bytes" 103 "context" 104 "errors" 105 "fmt" 106 stdLog "log" 107 "os" 108 "reflect" 109 "runtime" 110 "runtime/pprof" 111 "strconv" 112 "sync" 113 "sync/atomic" 114 "time" 115 116 "github.com/golang/glog/internal/logsink" 117 "github.com/golang/glog/internal/stackdump" 118 ) 119 120 var timeNow = time.Now // Stubbed out for testing. 121 122 // MaxSize is the maximum size of a log file in bytes. 123 var MaxSize uint64 = 1024 * 1024 * 1800 124 125 // ErrNoLog is the error we return if no log file has yet been created 126 // for the specified log type. 127 var ErrNoLog = errors.New("log file not yet created") 128 129 // OutputStats tracks the number of output lines and bytes written. 130 type OutputStats struct { 131 lines int64 132 bytes int64 133 } 134 135 // Lines returns the number of lines written. 136 func (s *OutputStats) Lines() int64 { 137 return atomic.LoadInt64(&s.lines) 138 } 139 140 // Bytes returns the number of bytes written. 141 func (s *OutputStats) Bytes() int64 { 142 return atomic.LoadInt64(&s.bytes) 143 } 144 145 // Stats tracks the number of lines of output and number of bytes 146 // per severity level. Values must be read with atomic.LoadInt64. 147 var Stats struct { 148 Info, Warning, Error OutputStats 149 } 150 151 var severityStats = [...]*OutputStats{ 152 logsink.Info: &Stats.Info, 153 logsink.Warning: &Stats.Warning, 154 logsink.Error: &Stats.Error, 155 logsink.Fatal: nil, 156 } 157 158 // Level specifies a level of verbosity for V logs. The -v flag is of type 159 // Level and should be modified only through the flag.Value interface. 160 type Level int32 161 162 var metaPool sync.Pool // Pool of *logsink.Meta. 163 164 // metaPoolGet returns a *logsink.Meta from metaPool as both an interface and a 165 // pointer, allocating a new one if necessary. (Returning the interface value 166 // directly avoids an allocation if there was an existing pointer in the pool.) 167 func metaPoolGet() (any, *logsink.Meta) { 168 if metai := metaPool.Get(); metai != nil { 169 return metai, metai.(*logsink.Meta) 170 } 171 meta := new(logsink.Meta) 172 return meta, meta 173 } 174 175 type stack bool 176 177 const ( 178 noStack = stack(false) 179 withStack = stack(true) 180 ) 181 182 func appendBacktrace(depth int, format string, args []any) (string, []any) { 183 // Capture a backtrace as a stackdump.Stack (both text and PC slice). 184 // Structured log sinks can extract the backtrace in whichever format they 185 // prefer (PCs or text), and Text sinks will include it as just another part 186 // of the log message. 187 // 188 // Use depth instead of depth+1 so that the backtrace always includes the 189 // log function itself - otherwise the reason for the trace appearing in the 190 // log may not be obvious to the reader. 191 dump := stackdump.Caller(depth) 192 193 // Add an arg and an entry in the format string for the stack dump. 194 // 195 // Copy the "args" slice to avoid a rare but serious aliasing bug 196 // (corrupting the caller's slice if they passed it to a non-Fatal call 197 // using "..."). 198 format = format + "\n\n%v\n" 199 args = append(append([]any(nil), args...), dump) 200 201 return format, args 202 } 203 204 // logf acts as ctxlogf, but doesn't expect a context. 205 func logf(depth int, severity logsink.Severity, verbose bool, stack stack, format string, args ...any) { 206 ctxlogf(nil, depth+1, severity, verbose, stack, format, args...) 207 } 208 209 // ctxlogf writes a log message for a log function call (or log function wrapper) 210 // at the given depth in the current goroutine's stack. 211 func ctxlogf(ctx context.Context, depth int, severity logsink.Severity, verbose bool, stack stack, format string, args ...any) { 212 now := timeNow() 213 _, file, line, ok := runtime.Caller(depth + 1) 214 if !ok { 215 file = "???" 216 line = 1 217 } 218 219 if stack == withStack || backtraceAt(file, line) { 220 format, args = appendBacktrace(depth+1, format, args) 221 } 222 223 metai, meta := metaPoolGet() 224 *meta = logsink.Meta{ 225 Context: ctx, 226 Time: now, 227 File: file, 228 Line: line, 229 Depth: depth + 1, 230 Severity: severity, 231 Verbose: verbose, 232 Thread: int64(pid), 233 } 234 sinkf(meta, format, args...) 235 // Clear pointer fields so they can be garbage collected early. 236 meta.Context = nil 237 meta.Stack = nil 238 metaPool.Put(metai) 239 } 240 241 func sinkf(meta *logsink.Meta, format string, args ...any) { 242 meta.Depth++ 243 n, err := logsink.Printf(meta, format, args...) 244 if stats := severityStats[meta.Severity]; stats != nil { 245 atomic.AddInt64(&stats.lines, 1) 246 atomic.AddInt64(&stats.bytes, int64(n)) 247 } 248 249 if err != nil { 250 logsink.Printf(meta, "glog: exiting because of error: %s", err) 251 sinks.file.Flush() 252 os.Exit(2) 253 } 254 } 255 256 // CopyStandardLogTo arranges for messages written to the Go "log" package's 257 // default logs to also appear in the Google logs for the named and lower 258 // severities. Subsequent changes to the standard log's default output location 259 // or format may break this behavior. 260 // 261 // Valid names are "INFO", "WARNING", "ERROR", and "FATAL". If the name is not 262 // recognized, CopyStandardLogTo panics. 263 func CopyStandardLogTo(name string) { 264 sev, err := logsink.ParseSeverity(name) 265 if err != nil { 266 panic(fmt.Sprintf("log.CopyStandardLogTo(%q): %v", name, err)) 267 } 268 // Set a log format that captures the user's file and line: 269 // d.go:23: message 270 stdLog.SetFlags(stdLog.Lshortfile) 271 stdLog.SetOutput(logBridge(sev)) 272 } 273 274 // NewStandardLogger returns a Logger that writes to the Google logs for the 275 // named and lower severities. 276 // 277 // Valid names are "INFO", "WARNING", "ERROR", and "FATAL". If the name is not 278 // recognized, NewStandardLogger panics. 279 func NewStandardLogger(name string) *stdLog.Logger { 280 sev, err := logsink.ParseSeverity(name) 281 if err != nil { 282 panic(fmt.Sprintf("log.NewStandardLogger(%q): %v", name, err)) 283 } 284 return stdLog.New(logBridge(sev), "", stdLog.Lshortfile) 285 } 286 287 // logBridge provides the Write method that enables CopyStandardLogTo to connect 288 // Go's standard logs to the logs provided by this package. 289 type logBridge logsink.Severity 290 291 // Write parses the standard logging line and passes its components to the 292 // logger for severity(lb). 293 func (lb logBridge) Write(b []byte) (n int, err error) { 294 var ( 295 file = "???" 296 line = 1 297 text string 298 ) 299 // Split "d.go:23: message" into "d.go", "23", and "message". 300 if parts := bytes.SplitN(b, []byte{':'}, 3); len(parts) != 3 || len(parts[0]) < 1 || len(parts[2]) < 1 { 301 text = fmt.Sprintf("bad log format: %s", b) 302 } else { 303 file = string(parts[0]) 304 text = string(parts[2][1:]) // skip leading space 305 line, err = strconv.Atoi(string(parts[1])) 306 if err != nil { 307 text = fmt.Sprintf("bad line number: %s", b) 308 line = 1 309 } 310 } 311 312 // The depth below hard-codes details of how stdlog gets here. The alternative would be to walk 313 // up the stack looking for src/log/log.go but that seems like it would be 314 // unfortunately slow. 315 const stdLogDepth = 4 316 317 metai, meta := metaPoolGet() 318 *meta = logsink.Meta{ 319 Time: timeNow(), 320 File: file, 321 Line: line, 322 Depth: stdLogDepth, 323 Severity: logsink.Severity(lb), 324 Thread: int64(pid), 325 } 326 327 format := "%s" 328 args := []any{text} 329 if backtraceAt(file, line) { 330 format, args = appendBacktrace(meta.Depth, format, args) 331 } 332 333 sinkf(meta, format, args...) 334 metaPool.Put(metai) 335 336 return len(b), nil 337 } 338 339 // defaultFormat returns a fmt.Printf format specifier that formats its 340 // arguments as if they were passed to fmt.Print. 341 func defaultFormat(args []any) string { 342 n := len(args) 343 switch n { 344 case 0: 345 return "" 346 case 1: 347 return "%v" 348 } 349 350 b := make([]byte, 0, n*3-1) 351 wasString := true // Suppress leading space. 352 for _, arg := range args { 353 isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String 354 if wasString || isString { 355 b = append(b, "%v"...) 356 } else { 357 b = append(b, " %v"...) 358 } 359 wasString = isString 360 } 361 return string(b) 362 } 363 364 // lnFormat returns a fmt.Printf format specifier that formats its arguments 365 // as if they were passed to fmt.Println. 366 func lnFormat(args []any) string { 367 if len(args) == 0 { 368 return "\n" 369 } 370 371 b := make([]byte, 0, len(args)*3) 372 for range args { 373 b = append(b, "%v "...) 374 } 375 b[len(b)-1] = '\n' // Replace the last space with a newline. 376 return string(b) 377 } 378 379 // Verbose is a boolean type that implements Infof (like Printf) etc. 380 // See the documentation of V for more information. 381 type Verbose bool 382 383 // V reports whether verbosity at the call site is at least the requested level. 384 // The returned value is a boolean of type Verbose, which implements Info, Infoln 385 // and Infof. These methods will write to the Info log if called. 386 // Thus, one may write either 387 // 388 // if glog.V(2) { glog.Info("log this") } 389 // 390 // or 391 // 392 // glog.V(2).Info("log this") 393 // 394 // The second form is shorter but the first is cheaper if logging is off because it does 395 // not evaluate its arguments. 396 // 397 // Whether an individual call to V generates a log record depends on the setting of 398 // the -v and --vmodule flags; both are off by default. If the level in the call to 399 // V is at most the value of -v, or of -vmodule for the source file containing the 400 // call, the V call will log. 401 func V(level Level) Verbose { 402 return VDepth(1, level) 403 } 404 405 // VDepth acts as V but uses depth to determine which call frame to check vmodule for. 406 // VDepth(0, level) is the same as V(level). 407 func VDepth(depth int, level Level) Verbose { 408 return Verbose(verboseEnabled(depth+1, level)) 409 } 410 411 // Info is equivalent to the global Info function, guarded by the value of v. 412 // See the documentation of V for usage. 413 func (v Verbose) Info(args ...any) { 414 v.InfoDepth(1, args...) 415 } 416 417 // InfoDepth is equivalent to the global InfoDepth function, guarded by the value of v. 418 // See the documentation of V for usage. 419 func (v Verbose) InfoDepth(depth int, args ...any) { 420 if v { 421 logf(depth+1, logsink.Info, true, noStack, defaultFormat(args), args...) 422 } 423 } 424 425 // InfoDepthf is equivalent to the global InfoDepthf function, guarded by the value of v. 426 // See the documentation of V for usage. 427 func (v Verbose) InfoDepthf(depth int, format string, args ...any) { 428 if v { 429 logf(depth+1, logsink.Info, true, noStack, format, args...) 430 } 431 } 432 433 // Infoln is equivalent to the global Infoln function, guarded by the value of v. 434 // See the documentation of V for usage. 435 func (v Verbose) Infoln(args ...any) { 436 if v { 437 logf(1, logsink.Info, true, noStack, lnFormat(args), args...) 438 } 439 } 440 441 // Infof is equivalent to the global Infof function, guarded by the value of v. 442 // See the documentation of V for usage. 443 func (v Verbose) Infof(format string, args ...any) { 444 if v { 445 logf(1, logsink.Info, true, noStack, format, args...) 446 } 447 } 448 449 // InfoContext is equivalent to the global InfoContext function, guarded by the value of v. 450 // See the documentation of V for usage. 451 func (v Verbose) InfoContext(ctx context.Context, args ...any) { 452 v.InfoContextDepth(ctx, 1, args...) 453 } 454 455 // InfoContextf is equivalent to the global InfoContextf function, guarded by the value of v. 456 // See the documentation of V for usage. 457 func (v Verbose) InfoContextf(ctx context.Context, format string, args ...any) { 458 if v { 459 ctxlogf(ctx, 1, logsink.Info, true, noStack, format, args...) 460 } 461 } 462 463 // InfoContextDepth is equivalent to the global InfoContextDepth function, guarded by the value of v. 464 // See the documentation of V for usage. 465 func (v Verbose) InfoContextDepth(ctx context.Context, depth int, args ...any) { 466 if v { 467 ctxlogf(ctx, depth+1, logsink.Info, true, noStack, defaultFormat(args), args...) 468 } 469 } 470 471 // InfoContextDepthf is equivalent to the global InfoContextDepthf function, guarded by the value of v. 472 // See the documentation of V for usage. 473 func (v Verbose) InfoContextDepthf(ctx context.Context, depth int, format string, args ...any) { 474 if v { 475 ctxlogf(ctx, depth+1, logsink.Info, true, noStack, format, args...) 476 } 477 } 478 479 // Info logs to the INFO log. 480 // Arguments are handled in the manner of fmt.Print; a newline is appended if missing. 481 func Info(args ...any) { 482 InfoDepth(1, args...) 483 } 484 485 // InfoDepth calls Info from a different depth in the call stack. 486 // This enables a callee to emit logs that use the callsite information of its caller 487 // or any other callers in the stack. When depth == 0, the original callee's line 488 // information is emitted. When depth > 0, depth frames are skipped in the call stack 489 // and the final frame is treated like the original callee to Info. 490 func InfoDepth(depth int, args ...any) { 491 logf(depth+1, logsink.Info, false, noStack, defaultFormat(args), args...) 492 } 493 494 // InfoDepthf acts as InfoDepth but with format string. 495 func InfoDepthf(depth int, format string, args ...any) { 496 logf(depth+1, logsink.Info, false, noStack, format, args...) 497 } 498 499 // Infoln logs to the INFO log. 500 // Arguments are handled in the manner of fmt.Println; a newline is appended if missing. 501 func Infoln(args ...any) { 502 logf(1, logsink.Info, false, noStack, lnFormat(args), args...) 503 } 504 505 // Infof logs to the INFO log. 506 // Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. 507 func Infof(format string, args ...any) { 508 logf(1, logsink.Info, false, noStack, format, args...) 509 } 510 511 // InfoContext is like [Info], but with an extra [context.Context] parameter. The 512 // context is used to pass the Trace Context to log sinks. 513 func InfoContext(ctx context.Context, args ...any) { 514 InfoContextDepth(ctx, 1, args...) 515 } 516 517 // InfoContextf is like [Infof], but with an extra [context.Context] parameter. The 518 // context is used to pass the Trace Context to log sinks. 519 func InfoContextf(ctx context.Context, format string, args ...any) { 520 ctxlogf(ctx, 1, logsink.Info, false, noStack, format, args...) 521 } 522 523 // InfoContextDepth is like [InfoDepth], but with an extra [context.Context] parameter. The 524 // context is used to pass the Trace Context to log sinks. 525 func InfoContextDepth(ctx context.Context, depth int, args ...any) { 526 ctxlogf(ctx, depth+1, logsink.Info, false, noStack, defaultFormat(args), args...) 527 } 528 529 // InfoContextDepthf is like [InfoDepthf], but with an extra [context.Context] parameter. The 530 // context is used to pass the Trace Context to log sinks. 531 func InfoContextDepthf(ctx context.Context, depth int, format string, args ...any) { 532 ctxlogf(ctx, depth+1, logsink.Info, false, noStack, format, args...) 533 } 534 535 // Warning logs to the WARNING and INFO logs. 536 // Arguments are handled in the manner of fmt.Print; a newline is appended if missing. 537 func Warning(args ...any) { 538 WarningDepth(1, args...) 539 } 540 541 // WarningDepth acts as Warning but uses depth to determine which call frame to log. 542 // WarningDepth(0, "msg") is the same as Warning("msg"). 543 func WarningDepth(depth int, args ...any) { 544 logf(depth+1, logsink.Warning, false, noStack, defaultFormat(args), args...) 545 } 546 547 // WarningDepthf acts as Warningf but uses depth to determine which call frame to log. 548 // WarningDepthf(0, "msg") is the same as Warningf("msg"). 549 func WarningDepthf(depth int, format string, args ...any) { 550 logf(depth+1, logsink.Warning, false, noStack, format, args...) 551 } 552 553 // Warningln logs to the WARNING and INFO logs. 554 // Arguments are handled in the manner of fmt.Println; a newline is appended if missing. 555 func Warningln(args ...any) { 556 logf(1, logsink.Warning, false, noStack, lnFormat(args), args...) 557 } 558 559 // Warningf logs to the WARNING and INFO logs. 560 // Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. 561 func Warningf(format string, args ...any) { 562 logf(1, logsink.Warning, false, noStack, format, args...) 563 } 564 565 // WarningContext is like [Warning], but with an extra [context.Context] parameter. The 566 // context is used to pass the Trace Context to log sinks. 567 func WarningContext(ctx context.Context, args ...any) { 568 WarningContextDepth(ctx, 1, args...) 569 } 570 571 // WarningContextf is like [Warningf], but with an extra [context.Context] parameter. The 572 // context is used to pass the Trace Context to log sinks. 573 func WarningContextf(ctx context.Context, format string, args ...any) { 574 ctxlogf(ctx, 1, logsink.Warning, false, noStack, format, args...) 575 } 576 577 // WarningContextDepth is like [WarningDepth], but with an extra [context.Context] parameter. The 578 // context is used to pass the Trace Context to log sinks. 579 func WarningContextDepth(ctx context.Context, depth int, args ...any) { 580 ctxlogf(ctx, depth+1, logsink.Warning, false, noStack, defaultFormat(args), args...) 581 } 582 583 // WarningContextDepthf is like [WarningDepthf], but with an extra [context.Context] parameter. The 584 // context is used to pass the Trace Context to log sinks. 585 func WarningContextDepthf(ctx context.Context, depth int, format string, args ...any) { 586 ctxlogf(ctx, depth+1, logsink.Warning, false, noStack, format, args...) 587 } 588 589 // Error logs to the ERROR, WARNING, and INFO logs. 590 // Arguments are handled in the manner of fmt.Print; a newline is appended if missing. 591 func Error(args ...any) { 592 ErrorDepth(1, args...) 593 } 594 595 // ErrorDepth acts as Error but uses depth to determine which call frame to log. 596 // ErrorDepth(0, "msg") is the same as Error("msg"). 597 func ErrorDepth(depth int, args ...any) { 598 logf(depth+1, logsink.Error, false, noStack, defaultFormat(args), args...) 599 } 600 601 // ErrorDepthf acts as Errorf but uses depth to determine which call frame to log. 602 // ErrorDepthf(0, "msg") is the same as Errorf("msg"). 603 func ErrorDepthf(depth int, format string, args ...any) { 604 logf(depth+1, logsink.Error, false, noStack, format, args...) 605 } 606 607 // Errorln logs to the ERROR, WARNING, and INFO logs. 608 // Arguments are handled in the manner of fmt.Println; a newline is appended if missing. 609 func Errorln(args ...any) { 610 logf(1, logsink.Error, false, noStack, lnFormat(args), args...) 611 } 612 613 // Errorf logs to the ERROR, WARNING, and INFO logs. 614 // Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. 615 func Errorf(format string, args ...any) { 616 logf(1, logsink.Error, false, noStack, format, args...) 617 } 618 619 // ErrorContext is like [Error], but with an extra [context.Context] parameter. The 620 // context is used to pass the Trace Context to log sinks. 621 func ErrorContext(ctx context.Context, args ...any) { 622 ErrorContextDepth(ctx, 1, args...) 623 } 624 625 // ErrorContextf is like [Errorf], but with an extra [context.Context] parameter. The 626 // context is used to pass the Trace Context to log sinks. 627 func ErrorContextf(ctx context.Context, format string, args ...any) { 628 ctxlogf(ctx, 1, logsink.Error, false, noStack, format, args...) 629 } 630 631 // ErrorContextDepth is like [ErrorDepth], but with an extra [context.Context] parameter. The 632 // context is used to pass the Trace Context to log sinks. 633 func ErrorContextDepth(ctx context.Context, depth int, args ...any) { 634 ctxlogf(ctx, depth+1, logsink.Error, false, noStack, defaultFormat(args), args...) 635 } 636 637 // ErrorContextDepthf is like [ErrorDepthf], but with an extra [context.Context] parameter. The 638 // context is used to pass the Trace Context to log sinks. 639 func ErrorContextDepthf(ctx context.Context, depth int, format string, args ...any) { 640 ctxlogf(ctx, depth+1, logsink.Error, false, noStack, format, args...) 641 } 642 643 func ctxfatalf(ctx context.Context, depth int, format string, args ...any) { 644 ctxlogf(ctx, depth+1, logsink.Fatal, false, withStack, format, args...) 645 sinks.file.Flush() 646 647 err := abortProcess() // Should not return. 648 649 // Failed to abort the process using signals. Dump a stack trace and exit. 650 Errorf("abortProcess returned unexpectedly: %v", err) 651 sinks.file.Flush() 652 pprof.Lookup("goroutine").WriteTo(os.Stderr, 1) 653 os.Exit(2) // Exit with the same code as the default SIGABRT handler. 654 } 655 656 func fatalf(depth int, format string, args ...any) { 657 ctxfatalf(nil, depth+1, format, args...) 658 } 659 660 // Fatal logs to the FATAL, ERROR, WARNING, and INFO logs, 661 // including a stack trace of all running goroutines, then calls os.Exit(2). 662 // Arguments are handled in the manner of fmt.Print; a newline is appended if missing. 663 func Fatal(args ...any) { 664 FatalDepth(1, args...) 665 } 666 667 // FatalDepth acts as Fatal but uses depth to determine which call frame to log. 668 // FatalDepth(0, "msg") is the same as Fatal("msg"). 669 func FatalDepth(depth int, args ...any) { 670 fatalf(depth+1, defaultFormat(args), args...) 671 } 672 673 // FatalDepthf acts as Fatalf but uses depth to determine which call frame to log. 674 // FatalDepthf(0, "msg") is the same as Fatalf("msg"). 675 func FatalDepthf(depth int, format string, args ...any) { 676 fatalf(depth+1, format, args...) 677 } 678 679 // Fatalln logs to the FATAL, ERROR, WARNING, and INFO logs, 680 // including a stack trace of all running goroutines, then calls os.Exit(2). 681 // Arguments are handled in the manner of fmt.Println; a newline is appended if missing. 682 func Fatalln(args ...any) { 683 fatalf(1, lnFormat(args), args...) 684 } 685 686 // Fatalf logs to the FATAL, ERROR, WARNING, and INFO logs, 687 // including a stack trace of all running goroutines, then calls os.Exit(2). 688 // Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. 689 func Fatalf(format string, args ...any) { 690 fatalf(1, format, args...) 691 } 692 693 // FatalContext is like [Fatal], but with an extra [context.Context] parameter. The 694 // context is used to pass the Trace Context to log sinks. 695 func FatalContext(ctx context.Context, args ...any) { 696 FatalContextDepth(ctx, 1, args...) 697 } 698 699 // FatalContextf is like [Fatalf], but with an extra [context.Context] parameter. The 700 // context is used to pass the Trace Context to log sinks. 701 func FatalContextf(ctx context.Context, format string, args ...any) { 702 ctxfatalf(ctx, 1, format, args...) 703 } 704 705 // FatalContextDepth is like [FatalDepth], but with an extra [context.Context] parameter. The 706 // context is used to pass the Trace Context to log sinks. 707 func FatalContextDepth(ctx context.Context, depth int, args ...any) { 708 ctxfatalf(ctx, depth+1, defaultFormat(args), args...) 709 } 710 711 // FatalContextDepthf is like [FatalDepthf], but with an extra [context.Context] parameter. 712 func FatalContextDepthf(ctx context.Context, depth int, format string, args ...any) { 713 ctxfatalf(ctx, depth+1, format, args...) 714 } 715 716 func ctxexitf(ctx context.Context, depth int, format string, args ...any) { 717 ctxlogf(ctx, depth+1, logsink.Fatal, false, noStack, format, args...) 718 sinks.file.Flush() 719 os.Exit(1) 720 } 721 722 func exitf(depth int, format string, args ...any) { 723 ctxexitf(nil, depth+1, format, args...) 724 } 725 726 // Exit logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1). 727 // Arguments are handled in the manner of fmt.Print; a newline is appended if missing. 728 func Exit(args ...any) { 729 ExitDepth(1, args...) 730 } 731 732 // ExitDepth acts as Exit but uses depth to determine which call frame to log. 733 // ExitDepth(0, "msg") is the same as Exit("msg"). 734 func ExitDepth(depth int, args ...any) { 735 exitf(depth+1, defaultFormat(args), args...) 736 } 737 738 // ExitDepthf acts as Exitf but uses depth to determine which call frame to log. 739 // ExitDepthf(0, "msg") is the same as Exitf("msg"). 740 func ExitDepthf(depth int, format string, args ...any) { 741 exitf(depth+1, format, args...) 742 } 743 744 // Exitln logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1). 745 func Exitln(args ...any) { 746 exitf(1, lnFormat(args), args...) 747 } 748 749 // Exitf logs to the FATAL, ERROR, WARNING, and INFO logs, then calls os.Exit(1). 750 // Arguments are handled in the manner of fmt.Printf; a newline is appended if missing. 751 func Exitf(format string, args ...any) { 752 exitf(1, format, args...) 753 } 754 755 // ExitContext is like [Exit], but with an extra [context.Context] parameter. The 756 // context is used to pass the Trace Context to log sinks. 757 func ExitContext(ctx context.Context, args ...any) { 758 ExitContextDepth(ctx, 1, args...) 759 } 760 761 // ExitContextf is like [Exitf], but with an extra [context.Context] parameter. The 762 // context is used to pass the Trace Context to log sinks. 763 func ExitContextf(ctx context.Context, format string, args ...any) { 764 ctxexitf(ctx, 1, format, args...) 765 } 766 767 // ExitContextDepth is like [ExitDepth], but with an extra [context.Context] parameter. The 768 // context is used to pass the Trace Context to log sinks. 769 func ExitContextDepth(ctx context.Context, depth int, args ...any) { 770 ctxexitf(ctx, depth+1, defaultFormat(args), args...) 771 } 772 773 // ExitContextDepthf is like [ExitDepthf], but with an extra [context.Context] parameter. The 774 // context is used to pass the Trace Context to log sinks. 775 func ExitContextDepthf(ctx context.Context, depth int, format string, args ...any) { 776 ctxexitf(ctx, depth+1, format, args...) 777 } 778