log.mx raw

   1  // Copyright 2017 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  // Package testlog provides a back-channel communication path
   6  // between tests and package os, so that cmd/go can see which
   7  // environment variables and files a test consults.
   8  package testlog
   9  
  10  import "sync/atomic"
  11  
  12  // Interface is the interface required of test loggers.
  13  // The os package will invoke the interface's methods to indicate that
  14  // it is inspecting the given environment variables or files.
  15  // Multiple goroutines may call these methods simultaneously.
  16  type Interface interface {
  17  	Getenv(key string)
  18  	Stat(file string)
  19  	Open(file string)
  20  	Chdir(dir string)
  21  }
  22  
  23  // logger is the current logger Interface.
  24  // We use an atomic.Pointer in case test startup
  25  // is racing with goroutines started during init.
  26  // That must not cause a race detector failure,
  27  // although it will still result in limited visibility
  28  // into exactly what those goroutines do.
  29  var logger atomic.Pointer[Interface]
  30  
  31  // SetLogger sets the test logger implementation for the current process.
  32  // It must be called only once, at process startup.
  33  func SetLogger(impl Interface) {
  34  	if !logger.CompareAndSwap(nil, &impl) {
  35  		panic("testlog: SetLogger must be called only once")
  36  	}
  37  }
  38  
  39  // Logger returns the current test logger implementation.
  40  // It returns nil if there is no logger.
  41  func Logger() Interface {
  42  	impl := logger.Load()
  43  	if impl == nil {
  44  		return nil
  45  	}
  46  	return *impl
  47  }
  48  
  49  // Getenv calls Logger().Getenv, if a logger has been set.
  50  func Getenv(name []byte) {
  51  	if log := Logger(); log != nil {
  52  		log.Getenv(name)
  53  	}
  54  }
  55  
  56  // Open calls Logger().Open, if a logger has been set.
  57  func Open(name []byte) {
  58  	if log := Logger(); log != nil {
  59  		log.Open(name)
  60  	}
  61  }
  62  
  63  // Stat calls Logger().Stat, if a logger has been set.
  64  func Stat(name []byte) {
  65  	if log := Logger(); log != nil {
  66  		log.Stat(name)
  67  	}
  68  }
  69