github.com/go-spring/spring-base@v1.1.3/log/log.go (about)

     1  /*
     2   * Copyright 2012-2019 the original author or authors.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *      https://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package log
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"errors"
    23  	"fmt"
    24  	"io"
    25  	"io/ioutil"
    26  	"os"
    27  	"path/filepath"
    28  	"sync"
    29  
    30  	"github.com/go-spring/spring-base/atomic"
    31  )
    32  
    33  // configLoggers 配置文件中的 Logger 对象,is safe for map[string]privateConfig.
    34  var configLoggers atomic.Value
    35  
    36  // usingLoggers 用户代码中的 Logger 对象,is safe for map[string]*Logger.
    37  var usingLoggers sync.Map
    38  
    39  type Initializer interface {
    40  	Init() error
    41  }
    42  
    43  type LifeCycle interface {
    44  	Start() error
    45  	Stop(ctx context.Context)
    46  }
    47  
    48  type privateConfigMap struct {
    49  	loggers map[string]privateConfig
    50  }
    51  
    52  func (m *privateConfigMap) Get(name string) privateConfig {
    53  	if v, ok := m.loggers[name]; ok {
    54  		return v
    55  	}
    56  	return m.loggers["<<ROOT>>"]
    57  }
    58  
    59  type loggerHolder interface {
    60  	Get() *Logger
    61  }
    62  
    63  type simLoggerHolder struct {
    64  	logger *Logger
    65  }
    66  
    67  func (h *simLoggerHolder) Get() *Logger {
    68  	return h.logger
    69  }
    70  
    71  type initLoggerHolder struct {
    72  	name   string
    73  	once   sync.Once
    74  	logger *Logger
    75  }
    76  
    77  func (h *initLoggerHolder) Get() *Logger {
    78  	h.once.Do(func() {
    79  		h.logger = newLogger(h.name)
    80  		m := configLoggers.Load().(*privateConfigMap)
    81  		h.logger.reconfigure(m.Get(h.name))
    82  	})
    83  	return h.logger
    84  }
    85  
    86  func GetLogger(name string) *Logger {
    87  
    88  	if configLoggers.Load() == nil {
    89  		panic(errors.New("should call refresh first"))
    90  	}
    91  
    92  	var h loggerHolder = &initLoggerHolder{name: name}
    93  	actual, loaded := usingLoggers.LoadOrStore(name, h)
    94  	if loaded {
    95  		return actual.(loggerHolder).Get()
    96  	}
    97  
    98  	h = &simLoggerHolder{logger: h.Get()}
    99  	usingLoggers.LoadOrStore(name, h)
   100  	return h.Get()
   101  }
   102  
   103  // Refresh 加载日志配置文件。
   104  func Refresh(fileName string) error {
   105  	ext := filepath.Ext(fileName)
   106  	file, err := os.Open(fileName)
   107  	if err != nil {
   108  		return err
   109  	}
   110  	defer file.Close()
   111  	return RefreshReader(file, ext)
   112  }
   113  
   114  // RefreshBuffer 加载日志配置文件。
   115  func RefreshBuffer(buffer string, ext string) error {
   116  	input := bytes.NewBufferString(buffer)
   117  	return RefreshReader(input, ext)
   118  }
   119  
   120  // RefreshReader 加载日志配置文件。
   121  func RefreshReader(input io.Reader, ext string) error {
   122  
   123  	var rootNode *Node
   124  	{
   125  		r, ok := readers[ext]
   126  		if !ok {
   127  			return fmt.Errorf("unsupported file type %s", ext)
   128  		}
   129  		data, err := ioutil.ReadAll(input)
   130  		if err != nil {
   131  			return err
   132  		}
   133  		rootNode, err = r.Read(data)
   134  		if err != nil {
   135  			return err
   136  		}
   137  	}
   138  
   139  	if rootNode.Label != "Configuration" {
   140  		return errors.New("the Configuration root not found")
   141  	}
   142  
   143  	var (
   144  		cRoot      privateConfig
   145  		cAppenders = make(map[string]Appender)
   146  		cLoggers   = make(map[string]privateConfig)
   147  	)
   148  
   149  	if node := rootNode.child("Appenders"); node != nil {
   150  		for _, c := range node.Children {
   151  			p, ok := plugins[c.Label]
   152  			if !ok {
   153  				return fmt.Errorf("plugin %s not found", c.Label)
   154  			}
   155  			name, ok := c.Attributes["name"]
   156  			if !ok {
   157  				return errors.New("attribute 'name' not found")
   158  			}
   159  			v, err := newPlugin(p.Class, c)
   160  			if err != nil {
   161  				return err
   162  			}
   163  			cAppenders[name] = v.Interface().(Appender)
   164  		}
   165  	}
   166  
   167  	if node := rootNode.child("Loggers"); node != nil {
   168  		for _, c := range node.Children {
   169  
   170  			isRootLogger := c.Label == "Root" || c.Label == "AsyncRoot"
   171  			if isRootLogger {
   172  				if cRoot != nil {
   173  					return errors.New("found more than one root loggers")
   174  				}
   175  				c.Attributes["name"] = "<<ROOT>>"
   176  			}
   177  
   178  			p, ok := plugins[c.Label]
   179  			if !ok || p == nil {
   180  				return fmt.Errorf("plugin %s not found", c.Label)
   181  			}
   182  			name, ok := c.Attributes["name"]
   183  			if !ok {
   184  				return errors.New("attribute 'name' not found")
   185  			}
   186  
   187  			v, err := newPlugin(p.Class, c)
   188  			if err != nil {
   189  				return err
   190  			}
   191  			config := v.Interface().(privateConfig)
   192  			if isRootLogger {
   193  				cRoot = config
   194  			}
   195  			cLoggers[name] = config
   196  		}
   197  	}
   198  
   199  	if cRoot == nil {
   200  		return errors.New("found no root logger")
   201  	}
   202  
   203  	for name, config := range cLoggers {
   204  
   205  		var base *baseLoggerConfig
   206  		switch v := config.(type) {
   207  		case *loggerConfig:
   208  			base = &v.baseLoggerConfig
   209  		case *asyncLoggerConfig:
   210  			base = &v.baseLoggerConfig
   211  		}
   212  
   213  		if name != cRoot.getName() {
   214  			base.root = cRoot
   215  		}
   216  
   217  		for _, r := range base.AppenderRefs {
   218  			appender, ok := cAppenders[r.Ref]
   219  			if !ok {
   220  				return fmt.Errorf("appender %s not found", r.Ref)
   221  			}
   222  			r.appender = appender
   223  		}
   224  	}
   225  
   226  	m := &privateConfigMap{cLoggers}
   227  	configLoggers.Store(m)
   228  
   229  	// 对用户代码中的 Logger 对象应用最新的配置。
   230  	usingLoggers.Range(func(key, value interface{}) bool {
   231  		l := value.(loggerHolder).Get()
   232  		l.reconfigure(m.Get(key.(string)))
   233  		return true
   234  	})
   235  
   236  	return nil
   237  }