github.com/ablease/cli@v6.37.1-0.20180613014814-3adbb7d7fb19+incompatible/actor/v2action/logging.go (about)

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