github.com/drone/runner-go@v1.12.0/logger/history/history.go (about) 1 // Copyright 2019 Drone.IO Inc. All rights reserved. 2 // Use of this source code is governed by the Polyform License 3 // that can be found in the LICENSE file. 4 5 package history 6 7 // Package history implements a logrus hook that provides access 8 // to log recent log activity. 9 import ( 10 "sync" 11 12 "github.com/sirupsen/logrus" 13 ) 14 15 // default log entry limit. 16 const defaultLimit = 250 17 18 // Level is the log level. 19 type Level string 20 21 // log levels. 22 const ( 23 LevelError = Level("error") 24 LevelWarn = Level("warn") 25 LevelInfo = Level("info") 26 LevelDebug = Level("debug") 27 LevelTrace = Level("trace") 28 ) 29 30 // Entry provides a log entry. 31 type Entry struct { 32 Level Level 33 Message string 34 Data map[string]interface{} 35 Unix int64 36 } 37 38 // Hook is a logrus hook that track the log history. 39 type Hook struct { 40 sync.RWMutex 41 limit int 42 entries []*Entry 43 } 44 45 // New returns a new history hook. 46 func New() *Hook { 47 return NewLimit(defaultLimit) 48 } 49 50 // NewLimit returns a new history hook with a custom 51 // history limit. 52 func NewLimit(limit int) *Hook { 53 return &Hook{limit: limit} 54 } 55 56 // Fire receives the log entry. 57 func (h *Hook) Fire(e *logrus.Entry) error { 58 h.Lock() 59 if len(h.entries) >= h.limit { 60 h.entries = h.entries[1:] 61 } 62 h.entries = append(h.entries, &Entry{ 63 Level: convertLevel(e.Level), 64 Data: convertFields(e.Data), 65 Unix: e.Time.Unix(), 66 Message: e.Message, 67 }) 68 h.Unlock() 69 return nil 70 } 71 72 // Levels returns the supported log levels. 73 func (h *Hook) Levels() []logrus.Level { 74 return logrus.AllLevels 75 } 76 77 // Entries returns a list of all entries. 78 func (h *Hook) Entries() []*Entry { 79 h.RLock() 80 defer h.RUnlock() 81 entries := make([]*Entry, len(h.entries)) 82 for i, entry := range h.entries { 83 entries[i] = copyEntry(entry) 84 } 85 return entries 86 } 87 88 // Filter returns a list of all entries for which the filter 89 // function returns true. 90 func (h *Hook) Filter(filter func(*Entry) bool) []*Entry { 91 h.RLock() 92 defer h.RUnlock() 93 var entries []*Entry 94 for _, entry := range h.entries { 95 if filter(entry) { 96 entries = append(entries, copyEntry(entry)) 97 } 98 } 99 return entries 100 } 101 102 // helper funtion copies an entry for threadsafe access. 103 func copyEntry(src *Entry) *Entry { 104 dst := new(Entry) 105 *dst = *src 106 dst.Data = map[string]interface{}{} 107 for k, v := range src.Data { 108 dst.Data[k] = v 109 } 110 return dst 111 } 112 113 // helper function converts a logrus.Level to the local type. 114 func convertLevel(level logrus.Level) Level { 115 switch level { 116 case logrus.PanicLevel: 117 return LevelError 118 case logrus.FatalLevel: 119 return LevelError 120 case logrus.ErrorLevel: 121 return LevelError 122 case logrus.WarnLevel: 123 return LevelWarn 124 case logrus.DebugLevel: 125 return LevelDebug 126 case logrus.TraceLevel: 127 return LevelTrace 128 default: 129 return LevelInfo 130 } 131 } 132 133 // helper fucntion copies logrus.Fields to a basic map. 134 func convertFields(src logrus.Fields) map[string]interface{} { 135 dst := map[string]interface{}{} 136 for k, v := range src { 137 dst[k] = v 138 } 139 return dst 140 }