github.com/loggregator/cli@v6.33.1-0.20180224010324-82334f081791+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 }