github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/logger/sys.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package logger
    18  
    19  import (
    20  	"fmt"
    21  	"sync"
    22  	"time"
    23  )
    24  
    25  // mlogLogRollIntervalDefault determines how often mlog files should roll
    26  const mlogLogRollIntervalDefault = 30 * time.Minute
    27  
    28  type stdMsg struct {
    29  	level LogLevel
    30  	msg   string
    31  }
    32  
    33  type jsonMsg []byte
    34  
    35  func (m jsonMsg) Level() LogLevel {
    36  	return 0
    37  }
    38  
    39  func (m jsonMsg) String() string {
    40  	return string(m)
    41  }
    42  
    43  type LogMsg interface {
    44  	Level() LogLevel
    45  	fmt.Stringer
    46  }
    47  
    48  func (m stdMsg) Level() LogLevel {
    49  	return m.level
    50  }
    51  
    52  func (m stdMsg) String() string {
    53  	return m.msg
    54  }
    55  
    56  var (
    57  	logMessageC = make(chan LogMsg)
    58  	addSystemC  = make(chan LogSystem)
    59  	flushC      = make(chan chan struct{})
    60  	resetC      = make(chan chan struct{})
    61  )
    62  
    63  func init() {
    64  	go dispatchLoop()
    65  }
    66  
    67  // each system can buffer this many messages before
    68  // blocking incoming log messages.
    69  const sysBufferSize = 500
    70  
    71  func dispatchLoop() {
    72  	var (
    73  		systems  []LogSystem
    74  		systemIn []chan LogMsg
    75  		systemWG sync.WaitGroup
    76  	)
    77  	bootSystem := func(sys LogSystem) {
    78  		in := make(chan LogMsg, sysBufferSize)
    79  		systemIn = append(systemIn, in)
    80  		systemWG.Add(1)
    81  		go sysLoop(sys, in, &systemWG)
    82  	}
    83  
    84  	var tick = time.NewTicker(mlogLogRollIntervalDefault)
    85  
    86  	for {
    87  		select {
    88  		// HACK: quick and dirty, but cheap, way to get mlog file rotation
    89  		case <-tick.C:
    90  			for _, s := range systems {
    91  				if c, ok := s.(*MLogSystem); ok {
    92  					if l := c.GetLogger(); l != nil {
    93  						l.SetOutput(c.NewFile())
    94  					}
    95  				}
    96  			}
    97  		case msg := <-logMessageC:
    98  			for _, c := range systemIn {
    99  				c <- msg
   100  			}
   101  
   102  		case sys := <-addSystemC:
   103  			systems = append(systems, sys)
   104  			bootSystem(sys)
   105  
   106  		case waiter := <-resetC:
   107  			// reset means terminate all systems
   108  			for _, c := range systemIn {
   109  				close(c)
   110  			}
   111  			systems = nil
   112  			systemIn = nil
   113  			systemWG.Wait()
   114  			close(waiter)
   115  
   116  		case waiter := <-flushC:
   117  			// flush means reboot all systems
   118  			for _, c := range systemIn {
   119  				close(c)
   120  			}
   121  			systemIn = nil
   122  			systemWG.Wait()
   123  			for _, sys := range systems {
   124  				bootSystem(sys)
   125  			}
   126  			close(waiter)
   127  		}
   128  	}
   129  }
   130  
   131  func sysLoop(sys LogSystem, in <-chan LogMsg, wg *sync.WaitGroup) {
   132  	for msg := range in {
   133  		sys.LogPrint(msg)
   134  	}
   135  	wg.Done()
   136  }
   137  
   138  // Reset removes all active log systems.
   139  // It blocks until all current messages have been delivered.
   140  func Reset() {
   141  	waiter := make(chan struct{})
   142  	resetC <- waiter
   143  	<-waiter
   144  }
   145  
   146  // Flush waits until all current log messages have been dispatched to
   147  // the active log systems.
   148  func Flush() {
   149  	waiter := make(chan struct{})
   150  	flushC <- waiter
   151  	<-waiter
   152  }
   153  
   154  // AddLogSystem starts printing messages to the given LogSystem.
   155  func AddLogSystem(sys LogSystem) {
   156  	addSystemC <- sys
   157  }