github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/lib/log/serverlogger/impl.go (about)

     1  package serverlogger
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"log"
     7  	"os"
     8  	"regexp"
     9  	"runtime"
    10  	"strings"
    11  	"sync"
    12  	"time"
    13  
    14  	liblog "github.com/Cloud-Foundations/Dominator/lib/log"
    15  	"github.com/Cloud-Foundations/Dominator/lib/logbuf"
    16  	"github.com/Cloud-Foundations/Dominator/lib/srpc"
    17  	"github.com/Cloud-Foundations/Dominator/lib/srpc/serverutil"
    18  	proto "github.com/Cloud-Foundations/Dominator/proto/logger"
    19  )
    20  
    21  type loggerMapT struct {
    22  	*serverutil.PerUserMethodLimiter
    23  	sync.Mutex
    24  	loggerMap map[string]*Logger
    25  }
    26  
    27  type grabWriter struct {
    28  	data []byte
    29  }
    30  
    31  var loggerMap *loggerMapT = &loggerMapT{
    32  	loggerMap: make(map[string]*Logger),
    33  	PerUserMethodLimiter: serverutil.NewPerUserMethodLimiter(
    34  		map[string]uint{
    35  			"Debug":         1,
    36  			"Print":         1,
    37  			"SetDebugLevel": 1,
    38  			"Watch":         1,
    39  		}),
    40  }
    41  
    42  func init() {
    43  	srpc.RegisterName("Logger", loggerMap)
    44  }
    45  
    46  func getCallerName(depth int) string {
    47  	if pc, _, _, ok := runtime.Caller(depth); !ok {
    48  		return "UNKNOWN"
    49  	} else if fi := runtime.FuncForPC(pc); fi == nil {
    50  		return "UNKNOWN"
    51  	} else if splitName := strings.Split(fi.Name(), "."); len(splitName) < 1 {
    52  		return "UNKNOWN"
    53  	} else {
    54  		return splitName[len(splitName)-1]
    55  	}
    56  }
    57  
    58  func (w *grabWriter) Write(p []byte) (int, error) {
    59  	w.data = p
    60  	return len(p), nil
    61  }
    62  
    63  func newLogger(name string, options logbuf.Options, flags int) *Logger {
    64  	loggerMap.Lock()
    65  	defer loggerMap.Unlock()
    66  	if _, ok := loggerMap.loggerMap[name]; ok {
    67  		panic("logger already exists: " + name)
    68  	}
    69  	circularBuffer := logbuf.NewWithOptions(options)
    70  	logger := &Logger{
    71  		circularBuffer: circularBuffer,
    72  		flags:          flags,
    73  		level:          int16(*initialLogDebugLevel),
    74  		streamers:      make(map[*streamerType]struct{}),
    75  	}
    76  	if logger.level < -1 {
    77  		logger.level = -1
    78  	}
    79  	logger.maxLevel = logger.level
    80  	// Ensure this satisfies the published interface.
    81  	var debugLogger liblog.FullDebugLogger
    82  	debugLogger = logger
    83  	_ = debugLogger
    84  	loggerMap.loggerMap[name] = logger
    85  	return logger
    86  }
    87  
    88  func (l *Logger) checkAuth(authInfo *srpc.AuthInformation) error {
    89  	if authInfo.HaveMethodAccess {
    90  		return nil
    91  	}
    92  	if accessChecker := l.accessChecker; accessChecker == nil {
    93  		return errors.New("no access to resource")
    94  	} else if accessChecker(getCallerName(3), authInfo) {
    95  		return nil
    96  	} else {
    97  		return errors.New("no access to resource")
    98  	}
    99  }
   100  
   101  func (l *Logger) debug(level int16, v ...interface{}) {
   102  	if l.maxLevel >= level {
   103  		l.log(level, fmt.Sprint(v...), false)
   104  	}
   105  }
   106  
   107  func (l *Logger) debugf(level int16, format string, v ...interface{}) {
   108  	if l.maxLevel >= level {
   109  		l.log(level, fmt.Sprintf(format, v...), false)
   110  	}
   111  }
   112  
   113  func (l *Logger) debugln(level int16, v ...interface{}) {
   114  	if l.maxLevel >= level {
   115  		l.log(level, fmt.Sprintln(v...), false)
   116  	}
   117  }
   118  
   119  func (l *Logger) fatals(msg string) {
   120  	l.log(-1, msg, true)
   121  	os.Exit(1)
   122  }
   123  
   124  func (l *Logger) log(level int16, msg string, dying bool) {
   125  	buffer := &grabWriter{}
   126  	rawLogger := log.New(buffer, "", l.flags)
   127  	rawLogger.Output(4, msg)
   128  	if l.level >= level {
   129  		l.circularBuffer.Write(buffer.data)
   130  	}
   131  	recalculateLevels := false
   132  	l.mutex.Lock()
   133  	defer l.mutex.Unlock()
   134  	for streamer := range l.streamers {
   135  		if streamer.debugLevel >= level &&
   136  			(streamer.includeRegex == nil ||
   137  				streamer.includeRegex.Match(buffer.data)) &&
   138  			(streamer.excludeRegex == nil ||
   139  				!streamer.excludeRegex.Match(buffer.data)) {
   140  			select {
   141  			case streamer.output <- buffer.data:
   142  			default:
   143  				delete(l.streamers, streamer)
   144  				close(streamer.output)
   145  				recalculateLevels = true
   146  			}
   147  		}
   148  	}
   149  	if dying {
   150  		for streamer := range l.streamers {
   151  			delete(l.streamers, streamer)
   152  			close(streamer.output)
   153  		}
   154  		l.circularBuffer.Flush()
   155  		time.Sleep(time.Millisecond * 10)
   156  	} else if recalculateLevels {
   157  		l.updateMaxLevel()
   158  	}
   159  }
   160  
   161  func (l *Logger) makeStreamer(request proto.WatchRequest) (
   162  	*streamerType, error) {
   163  	if request.DebugLevel < -1 {
   164  		request.DebugLevel = -1
   165  	}
   166  	streamer := &streamerType{debugLevel: request.DebugLevel}
   167  	if request.ExcludeRegex != "" {
   168  		var err error
   169  		streamer.excludeRegex, err = regexp.Compile(request.ExcludeRegex)
   170  		if err != nil {
   171  			return nil, err
   172  		}
   173  	}
   174  	if request.IncludeRegex != "" {
   175  		var err error
   176  		streamer.includeRegex, err = regexp.Compile(request.IncludeRegex)
   177  		if err != nil {
   178  			return nil, err
   179  		}
   180  	}
   181  	return streamer, nil
   182  }
   183  
   184  func (l *Logger) panics(msg string) {
   185  	l.log(-1, msg, true)
   186  	panic(msg)
   187  }
   188  
   189  func (l *Logger) prints(msg string) {
   190  	l.log(-1, msg, false)
   191  }
   192  
   193  func (l *Logger) setLevel(maxLevel int16) {
   194  	if maxLevel < -1 {
   195  		maxLevel = -1
   196  	}
   197  	l.level = maxLevel
   198  	l.mutex.Lock()
   199  	l.updateMaxLevel()
   200  	l.mutex.Unlock()
   201  }
   202  
   203  func (l *Logger) updateMaxLevel() {
   204  	maxLevel := l.level
   205  	for streamer := range l.streamers {
   206  		if streamer.debugLevel > maxLevel {
   207  			maxLevel = streamer.debugLevel
   208  		}
   209  	}
   210  	l.maxLevel = maxLevel
   211  }
   212  
   213  func (l *Logger) watch(conn *srpc.Conn, streamer *streamerType) {
   214  	channel := make(chan []byte, 256)
   215  	streamer.output = channel
   216  	l.mutex.Lock()
   217  	l.streamers[streamer] = struct{}{}
   218  	l.updateMaxLevel()
   219  	l.mutex.Unlock()
   220  	timer := time.NewTimer(time.Millisecond * 100)
   221  	flushPending := false
   222  	closeNotifier := conn.GetCloseNotifier()
   223  	for keepGoing := true; keepGoing; {
   224  		select {
   225  		case <-closeNotifier:
   226  			keepGoing = false
   227  			break
   228  		case data, ok := <-channel:
   229  			if !ok {
   230  				keepGoing = false
   231  				break
   232  			}
   233  			if _, err := conn.Write(data); err != nil {
   234  				keepGoing = false
   235  				break
   236  			}
   237  			if !flushPending {
   238  				timer.Reset(time.Millisecond * 100)
   239  				flushPending = true
   240  			}
   241  		case <-timer.C:
   242  			if conn.Flush() != nil {
   243  				keepGoing = false
   244  				break
   245  			}
   246  			flushPending = false
   247  		}
   248  	}
   249  	if flushPending {
   250  		conn.Flush()
   251  	}
   252  	l.mutex.Lock()
   253  	delete(l.streamers, streamer)
   254  	l.updateMaxLevel()
   255  	l.mutex.Unlock()
   256  	// Drain the channel.
   257  	for {
   258  		select {
   259  		case <-channel:
   260  		default:
   261  			return
   262  		}
   263  	}
   264  }
   265  
   266  func (t *loggerMapT) getLogger(name string,
   267  	authInfo *srpc.AuthInformation) (*Logger, error) {
   268  	loggerMap.Lock()
   269  	defer loggerMap.Unlock()
   270  	if logger, ok := loggerMap.loggerMap[name]; !ok {
   271  		return nil, errors.New("unknown logger: " + name)
   272  	} else if err := logger.checkAuth(authInfo); err != nil {
   273  		return nil, err
   274  	} else {
   275  		return logger, nil
   276  	}
   277  }
   278  
   279  func (t *loggerMapT) Debug(conn *srpc.Conn,
   280  	request proto.DebugRequest, reply *proto.DebugResponse) error {
   281  	authInfo := conn.GetAuthInformation()
   282  	if logger, err := t.getLogger(request.Name, authInfo); err != nil {
   283  		return err
   284  	} else {
   285  		logger.Debugf(request.Level, "Logger.Debug(%d): %s\n",
   286  			request.Level, strings.Join(request.Args, " "))
   287  		return nil
   288  	}
   289  }
   290  
   291  func (t *loggerMapT) Print(conn *srpc.Conn,
   292  	request proto.PrintRequest,
   293  	reply *proto.PrintResponse) error {
   294  	authInfo := conn.GetAuthInformation()
   295  	if logger, err := t.getLogger(request.Name, authInfo); err != nil {
   296  		return err
   297  	} else {
   298  		logger.Println("Logger.Print():", strings.Join(request.Args, " "))
   299  		return nil
   300  	}
   301  }
   302  
   303  func (t *loggerMapT) SetDebugLevel(conn *srpc.Conn,
   304  	request proto.SetDebugLevelRequest,
   305  	reply *proto.SetDebugLevelResponse) error {
   306  	authInfo := conn.GetAuthInformation()
   307  	if logger, err := t.getLogger(request.Name, authInfo); err != nil {
   308  		return err
   309  	} else {
   310  		logger.Printf("Logger.SetDebugLevel(%d)\n", request.Level)
   311  		logger.SetLevel(request.Level)
   312  		return nil
   313  	}
   314  }
   315  
   316  func (t *loggerMapT) Watch(conn *srpc.Conn) error {
   317  	var request proto.WatchRequest
   318  	if err := conn.Decode(&request); err != nil {
   319  		return err
   320  	}
   321  	authInfo := conn.GetAuthInformation()
   322  	if logger, err := t.getLogger(request.Name, authInfo); err != nil {
   323  		return conn.Encode(proto.WatchResponse{Error: err.Error()})
   324  	} else if streamer, err := logger.makeStreamer(request); err != nil {
   325  		return conn.Encode(proto.WatchResponse{Error: err.Error()})
   326  	} else {
   327  		if err := conn.Encode(proto.WatchResponse{}); err != nil {
   328  			return err
   329  		}
   330  		if err := conn.Flush(); err != nil {
   331  			return err
   332  		}
   333  		logger.watch(conn, streamer)
   334  		return srpc.ErrorCloseClient
   335  	}
   336  }