github.com/Cloud-Foundations/Dominator@v0.3.4/lib/log/serverlogger/impl.go (about)

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