github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+incompatible/actor/v3action/logging.go (about)

     1  package v3action
     2  
     3  import (
     4  	"sort"
     5  	"time"
     6  
     7  	noaaErrors "github.com/cloudfoundry/noaa/errors"
     8  	"github.com/cloudfoundry/sonde-go/events"
     9  )
    10  
    11  const StagingLog = "STG"
    12  
    13  var flushInterval = 300 * time.Millisecond
    14  
    15  type LogMessage struct {
    16  	message        string
    17  	messageType    events.LogMessage_MessageType
    18  	timestamp      time.Time
    19  	sourceType     string
    20  	sourceInstance string
    21  }
    22  
    23  func (log LogMessage) Message() string {
    24  	return log.message
    25  }
    26  
    27  func (log LogMessage) Type() string {
    28  	if log.messageType == events.LogMessage_OUT {
    29  		return "OUT"
    30  	}
    31  	return "ERR"
    32  }
    33  
    34  func (log LogMessage) Staging() bool {
    35  	return log.sourceType == StagingLog
    36  }
    37  
    38  func (log LogMessage) Timestamp() time.Time {
    39  	return log.timestamp
    40  }
    41  
    42  func (log LogMessage) SourceType() string {
    43  	return log.sourceType
    44  }
    45  
    46  func (log LogMessage) SourceInstance() string {
    47  	return log.sourceInstance
    48  }
    49  
    50  func NewLogMessage(message string, messageType int, timestamp time.Time, sourceType string, sourceInstance string) *LogMessage {
    51  	return &LogMessage{
    52  		message:        message,
    53  		messageType:    events.LogMessage_MessageType(messageType),
    54  		timestamp:      timestamp,
    55  		sourceType:     sourceType,
    56  		sourceInstance: sourceInstance,
    57  	}
    58  }
    59  
    60  type LogMessages []*LogMessage
    61  
    62  func (lm LogMessages) Len() int { return len(lm) }
    63  
    64  func (lm LogMessages) Less(i, j int) bool {
    65  	return lm[i].timestamp.Before(lm[j].timestamp)
    66  }
    67  
    68  func (lm LogMessages) Swap(i, j int) {
    69  	lm[i], lm[j] = lm[j], lm[i]
    70  }
    71  
    72  func (Actor) GetStreamingLogs(appGUID string, client NOAAClient) (<-chan *LogMessage, <-chan error) {
    73  	// Do not pass in token because client should have a TokenRefresher set
    74  	eventStream, errStream := client.TailingLogs(appGUID, "")
    75  
    76  	messages := make(chan *LogMessage)
    77  	errs := make(chan error)
    78  
    79  	go func() {
    80  		defer close(messages)
    81  		defer close(errs)
    82  
    83  		ticker := time.NewTicker(flushInterval)
    84  		defer ticker.Stop()
    85  
    86  		var logs LogMessages
    87  	dance:
    88  		for {
    89  			select {
    90  			case event, ok := <-eventStream:
    91  				if !ok {
    92  					break dance
    93  				}
    94  
    95  				logs = append(logs, &LogMessage{
    96  					message:        string(event.GetMessage()),
    97  					messageType:    event.GetMessageType(),
    98  					timestamp:      time.Unix(0, event.GetTimestamp()),
    99  					sourceInstance: event.GetSourceInstance(),
   100  					sourceType:     event.GetSourceType(),
   101  				})
   102  			case err, ok := <-errStream:
   103  				if !ok {
   104  					break dance
   105  				}
   106  
   107  				if _, ok := err.(noaaErrors.RetryError); ok {
   108  					break
   109  				}
   110  
   111  				if err != nil {
   112  					errs <- err
   113  				}
   114  			case <-ticker.C:
   115  				sort.Stable(logs)
   116  				for _, l := range logs {
   117  					messages <- l
   118  				}
   119  
   120  				logs = logs[0:0]
   121  			}
   122  		}
   123  	}()
   124  
   125  	return messages, errs
   126  }
   127  
   128  func (actor Actor) GetStreamingLogsForApplicationByNameAndSpace(appName string, spaceGUID string, client NOAAClient) (<-chan *LogMessage, <-chan error, Warnings, error) {
   129  	app, allWarnings, err := actor.GetApplicationByNameAndSpace(appName, spaceGUID)
   130  	if err != nil {
   131  		return nil, nil, allWarnings, err
   132  	}
   133  
   134  	messages, logErrs := actor.GetStreamingLogs(app.GUID, client)
   135  
   136  	return messages, logErrs, allWarnings, err
   137  }