github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/debuglog_db.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package apiserver
     5  
     6  import (
     7  	"net/http"
     8  	"time"
     9  
    10  	"github.com/juju/clock"
    11  	"github.com/juju/errors"
    12  
    13  	"github.com/juju/juju/apiserver/authentication"
    14  	corelogger "github.com/juju/juju/core/logger"
    15  	"github.com/juju/juju/rpc/params"
    16  	"github.com/juju/juju/state"
    17  )
    18  
    19  func newDebugLogDBHandler(
    20  	ctxt httpContext,
    21  	authenticator authentication.HTTPAuthenticator,
    22  	authorizer authentication.Authorizer,
    23  ) http.Handler {
    24  	return newDebugLogHandler(ctxt, authenticator, authorizer, handleDebugLogDBRequest)
    25  }
    26  
    27  func handleDebugLogDBRequest(
    28  	clock clock.Clock,
    29  	maxDuration time.Duration,
    30  	st state.LogTailerState,
    31  	reqParams debugLogParams,
    32  	socket debugLogSocket,
    33  	stop <-chan struct{},
    34  ) error {
    35  	tailerParams := makeLogTailerParams(reqParams)
    36  	tailer, err := newLogTailer(st, tailerParams)
    37  	if err != nil {
    38  		return errors.Trace(err)
    39  	}
    40  	defer func() { _ = tailer.Stop() }()
    41  
    42  	// Indicate that all is well.
    43  	socket.sendOk()
    44  
    45  	timeout := clock.After(maxDuration)
    46  
    47  	var lineCount uint
    48  	for {
    49  		select {
    50  		case <-stop:
    51  			return nil
    52  		case <-timeout:
    53  			return nil
    54  		case rec, ok := <-tailer.Logs():
    55  			if !ok {
    56  				return errors.Annotate(tailer.Err(), "tailer stopped")
    57  			}
    58  
    59  			if err := socket.sendLogRecord(formatLogRecord(rec)); err != nil {
    60  				return errors.Annotate(err, "sending failed")
    61  			}
    62  
    63  			lineCount++
    64  			if reqParams.maxLines > 0 && lineCount == reqParams.maxLines {
    65  				return nil
    66  			}
    67  		}
    68  	}
    69  }
    70  
    71  func makeLogTailerParams(reqParams debugLogParams) corelogger.LogTailerParams {
    72  	tailerParams := corelogger.LogTailerParams{
    73  		MinLevel:      reqParams.filterLevel,
    74  		NoTail:        reqParams.noTail,
    75  		StartTime:     reqParams.startTime,
    76  		InitialLines:  int(reqParams.backlog),
    77  		IncludeEntity: reqParams.includeEntity,
    78  		ExcludeEntity: reqParams.excludeEntity,
    79  		IncludeModule: reqParams.includeModule,
    80  		ExcludeModule: reqParams.excludeModule,
    81  		IncludeLabel:  reqParams.includeLabel,
    82  		ExcludeLabel:  reqParams.excludeLabel,
    83  	}
    84  	if reqParams.fromTheStart {
    85  		tailerParams.InitialLines = 0
    86  	}
    87  	return tailerParams
    88  }
    89  
    90  func formatLogRecord(r *corelogger.LogRecord) *params.LogMessage {
    91  	return &params.LogMessage{
    92  		Entity:    r.Entity,
    93  		Timestamp: r.Time,
    94  		Severity:  r.Level.String(),
    95  		Module:    r.Module,
    96  		Location:  r.Location,
    97  		Message:   r.Message,
    98  		Labels:    r.Labels,
    99  	}
   100  }
   101  
   102  var newLogTailer = _newLogTailer // For replacing in tests
   103  
   104  func _newLogTailer(st state.LogTailerState, params corelogger.LogTailerParams) (corelogger.LogTailer, error) {
   105  	return state.NewLogTailer(st, params, nil)
   106  }