Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/soong/ui/logger/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 10 kB image not shown  

Quelle  logger.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2017 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 logger implements a logging package designed for command line
// utilities.  It uses the standard 'log' package and function, but splits
// output between stderr and a rotating log file.
//
// In addition to the standard logger functions, Verbose[f|ln] calls only go to
// the log file by default, unless SetVerbose(true) has been called.
//
// The log file also includes extended date/time/source information, which are
// omitted from the stderr output for better readability.
//
// In order to better handle resource cleanup after a Fatal error, the Fatal
// functions panic instead of calling os.Exit(). To actually do the cleanup,
// and prevent the printing of the panic, call defer logger.Cleanup() at the
// beginning of your main function.
package logger

import (
 "android/soong/ui/metrics"
 "bytes"
 "errors"
 "fmt"
 "io"
 "log"
 "os"
 "path/filepath"
 "strconv"
 "sync"
 "syscall"
)

type Logger interface {
 // Print* prints to both stderr and the file log.
 // Arguments to Print are handled in the manner of fmt.Print.
 Print(v ...interface{})
 // Arguments to Printf are handled in the manner of fmt.Printf
 Printf(format string, v ...interface{})
 // Arguments to Println are handled in the manner of fmt.Println
 Println(v ...interface{})

 // Verbose* is equivalent to Print*, but skips stderr unless the
 // logger has been configured in verbose mode.
 Verbose(v ...interface{})
 Verbosef(format string, v ...interface{})
 Verboseln(v ...interface{})

 // Fatal* is equivalent to Print* followed by a call to panic that
 // can be converted to an error using Recover, or will be converted
 // to a call to os.Exit(1) with a deferred call to Cleanup()
 Fatal(v ...interface{})
 Fatalf(format string, v ...interface{})
 Fatalln(v ...interface{})

 // Panic is equivalent to Print* followed by a call to panic.
 Panic(v ...interface{})
 Panicf(format string, v ...interface{})
 Panicln(v ...interface{})

 // Output writes the string to both stderr and the file log.
 Output(calldepth int, str string) error
}

// fatalError is the type used when Fatal[f|ln]
type fatalError struct {
 error
}

func fileRotation(from, baseName, ext string, cur, max int) error {
 newName := baseName + "." + strconv.Itoa(cur) + ext

 if _, err := os.Lstat(newName); err == nil {
  if cur+1 <= max {
   fileRotation(newName, baseName, ext, cur+1, max)
  }
 }

 if err := os.Rename(from, newName); err != nil {
  return fmt.Errorf("Failed to rotate %s to %s. %s", from, newName, err)
 }
 return nil
}

// CreateFileWithRotation returns a new os.File using os.Create, renaming any
// existing files to <filename>.#.<ext>, keeping up to maxCount files.
// <filename>.1.<ext> is the most recent backup, <filename>.2.<ext> is the
// second most recent backup, etc.
func CreateFileWithRotation(filename string, maxCount int) (*os.File, error) {
 lockFileName := filepath.Join(filepath.Dir(filename), ".lock_"+filepath.Base(filename))
 lockFile, err := os.OpenFile(lockFileName, os.O_RDWR|os.O_CREATE, 0666)
 if err != nil {
  return nil, err
 }
 defer lockFile.Close()

 err = syscall.Flock(int(lockFile.Fd()), syscall.LOCK_EX)
 if err != nil {
  return nil, err
 }

 if _, err := os.Lstat(filename); err == nil {
  ext := filepath.Ext(filename)
  basename := filename[:len(filename)-len(ext)]
  if err = fileRotation(filename, basename, ext, 1, maxCount); err != nil {
   return nil, err
  }
 }

 return os.Create(filename)
}

// Recover can be used with defer in a GoRoutine to convert a Fatal panics to
// an error that can be handled.
func Recover(fn func(err error)) {
 p := recover()

 if p == nil {
  return
 } else if log, ok := p.(fatalError); ok {
  fn(error(log))
 } else {
  panic(p)
 }
}

type stdLogger struct {
 stderr  *log.Logger
 verbose bool

 bufferedOutput *bytes.Buffer
 fileLogger     *log.Logger
 mutex          sync.Mutex
 file           *os.File
 metrics        *metrics.Metrics
}

var _ Logger = &stdLogger{}

// New creates a new Logger. The out variable sets the destination, commonly
// os.Stderr, but it may be a buffer for tests, or a separate log file if
// the user doesn't need to see the output.
func New(out io.Writer) *stdLogger {
 return NewWithMetrics(out, nil)
}

func NewWithMetrics(out io.Writer, m *metrics.Metrics) *stdLogger {
 // Buffer verbose output until the output file is set.
 bufferedOutput := new(bytes.Buffer)
 return &stdLogger{
  stderr:         log.New(out, "", log.Ltime),
  bufferedOutput: bufferedOutput,
  fileLogger:     log.New(bufferedOutput, "", log.Ldate|log.Lmicroseconds|log.Llongfile),
  metrics:        m,
 }
}

// SetVerbose controls whether Verbose[f|ln] logs to stderr as well as the
// file-backed log.
func (s *stdLogger) SetVerbose(v bool) *stdLogger {
 s.verbose = v
 return s
}

// SetOutput controls where the file-backed log will be saved. It will keep
// some number of backups of old log files.
func (s *stdLogger) SetOutput(path string) *stdLogger {
 if f, err := CreateFileWithRotation(path, 5); err == nil {
  s.mutex.Lock()
  defer s.mutex.Unlock()

  if s.file != nil {
   s.file.Close()
  }
  s.file = f
  // Copy any buffered output to the new file.
  _, err := io.Copy(f, s.bufferedOutput)
  if err != nil {
   panic(err)
  }
  s.bufferedOutput.Reset()
  s.fileLogger.SetOutput(f)
 } else {
  s.Fatal(err.Error())
 }
 return s
}

type panicWriter struct{}

func (panicWriter) Write([]byte) (int, error) { panic("write to panicWriter") }

// Close disables logging to the file and closes the file handle.
func (s *stdLogger) Close() {
 s.mutex.Lock()
 defer s.mutex.Unlock()
 if s.file != nil {
  s.fileLogger.SetOutput(panicWriter{})
  s.file.Close()
  s.file = nil
 }
}

// Cleanup should be used with defer in your main function. It will close the
// log file and convert any Fatal panics back to os.Exit(1)
func (s *stdLogger) Cleanup() {
 fatal := false
 p := recover()

 if _, ok := p.(fatalError); ok {
  fatal = true
  p = nil
 } else if p != nil {
  s.Println(p)
 }

 s.Close()

 if p != nil {
  panic(p)
 } else if fatal {
  os.Exit(1)
 }
}

type verbosityLevel int

const (
 verboseLog verbosityLevel = iota
 infoLog
 fatalLog
 panicLog
)

// Output writes string to both stderr and the file log.
func (s *stdLogger) Output(calldepth int, str string) error {
 return s.output(calldepth, str, infoLog)
}

// output writes string to stderr, the file log, and if fatal or panic, to metrics.
func (s *stdLogger) output(calldepth int, str string, level verbosityLevel) error {
 if level != verboseLog || s.verbose {
  s.stderr.Output(calldepth+1, str)
 }
 if level >= fatalLog {
  s.metrics.SetFatalOrPanicMessage(str)
 }
 return s.fileLogger.Output(calldepth+1, str)
}

// VerboseOutput is equivalent to Output, but only goes to the file log
// unless SetVerbose(true) has been called.
func (s *stdLogger) VerboseOutput(calldepth int, str string) error {
 return s.output(calldepth, str, verboseLog)
}

// Print prints to both stderr and the file log.
// Arguments are handled in the manner of fmt.Print.
func (s *stdLogger) Print(v ...interface{}) {
 output := fmt.Sprint(v...)
 s.output(2, output, infoLog)
}

// Printf prints to both stderr and the file log.
// Arguments are handled in the manner of fmt.Printf.
func (s *stdLogger) Printf(format string, v ...interface{}) {
 output := fmt.Sprintf(format, v...)
 s.output(2, output, infoLog)
}

// Println prints to both stderr and the file log.
// Arguments are handled in the manner of fmt.Println.
func (s *stdLogger) Println(v ...interface{}) {
 output := fmt.Sprintln(v...)
 s.output(2, output, infoLog)
}

// Verbose is equivalent to Print, but only goes to the file log unless
// SetVerbose(true) has been called.
func (s *stdLogger) Verbose(v ...interface{}) {
 output := fmt.Sprint(v...)
 s.VerboseOutput(2, output)
}

// Verbosef is equivalent to Printf, but only goes to the file log unless
// SetVerbose(true) has been called.
func (s *stdLogger) Verbosef(format string, v ...interface{}) {
 output := fmt.Sprintf(format, v...)
 s.VerboseOutput(2, output)
}

// Verboseln is equivalent to Println, but only goes to the file log unless
// SetVerbose(true) has been called.
func (s *stdLogger) Verboseln(v ...interface{}) {
 output := fmt.Sprintln(v...)
 s.VerboseOutput(2, output)
}

// Fatal is equivalent to Print() followed by a call to panic() that
// Cleanup will convert to a os.Exit(1).
func (s *stdLogger) Fatal(v ...interface{}) {
 output := fmt.Sprint(v...)
 s.output(2, output, fatalLog)
 panic(fatalError{errors.New(output)})
}

// Fatalf is equivalent to Printf() followed by a call to panic() that
// Cleanup will convert to a os.Exit(1).
func (s *stdLogger) Fatalf(format string, v ...interface{}) {
 output := fmt.Sprintf(format, v...)
 s.output(2, output, fatalLog)
 panic(fatalError{errors.New(output)})
}

// Fatalln is equivalent to Println() followed by a call to panic() that
// Cleanup will convert to a os.Exit(1).
func (s *stdLogger) Fatalln(v ...interface{}) {
 output := fmt.Sprintln(v...)
 s.output(2, output, fatalLog)
 panic(fatalError{errors.New(output)})
}

// Panic is equivalent to Print() followed by a call to panic().
func (s *stdLogger) Panic(v ...interface{}) {
 output := fmt.Sprint(v...)
 s.output(2, output, panicLog)
 panic(output)
}

// Panicf is equivalent to Printf() followed by a call to panic().
func (s *stdLogger) Panicf(format string, v ...interface{}) {
 output := fmt.Sprintf(format, v...)
 s.output(2, output, panicLog)
 panic(output)
}

// Panicln is equivalent to Println() followed by a call to panic().
func (s *stdLogger) Panicln(v ...interface{}) {
 output := fmt.Sprintln(v...)
 s.output(2, output, panicLog)
 panic(output)
}

[Dauer der Verarbeitung: 0.20 Sekunden, vorverarbeitet 2026-06-28]