github.com/mongodb/grip@v0.0.0-20240213223901-f906268d82b9/message/group.go (about) 1 package message 2 3 import ( 4 "fmt" 5 "strings" 6 "sync" 7 8 "github.com/mongodb/grip/level" 9 ) 10 11 // GroupComposer handles groups of composers as a single message, 12 // joining messages with a new line for the string format and returning a 13 // slice of interfaces for the Raw() form. 14 // 15 // Unlike most composer types, the GroupComposer is exported, and 16 // provides the additional Messages() method to access the composer 17 // objects as a slice. 18 type GroupComposer struct { 19 messages []Composer 20 mutex sync.RWMutex 21 } 22 23 // NewGroupComposer returns a GroupComposer object from a slice of 24 // Composers. 25 func NewGroupComposer(msgs []Composer) Composer { 26 return &GroupComposer{ 27 messages: msgs, 28 } 29 } 30 31 // NewGroupComposerWithPriority constructs a group composer from a collection of composers. 32 func NewGroupComposerWithPriority(p level.Priority, msgs []Composer) Composer { 33 cmp := NewGroupComposer(msgs) 34 _ = cmp.SetPriority(p) 35 return cmp 36 } 37 38 // MakeGroupComposer provides a variadic interface for creating a 39 // GroupComposer. 40 func MakeGroupComposer(msgs ...Composer) Composer { 41 return NewGroupComposer(msgs) 42 } 43 44 // String satisfies the fmt.Stringer interface, and returns a string 45 // of the string form of all constituent composers joined with a newline. 46 func (g *GroupComposer) String() string { 47 g.mutex.RLock() 48 defer g.mutex.RUnlock() 49 50 if len(g.messages) == 1 && g.messages[0].Loggable() { 51 return g.messages[0].String() 52 53 } 54 55 out := []string{} 56 for _, m := range g.messages { 57 if m == nil { 58 continue 59 } 60 if m.Loggable() { 61 out = append(out, m.String()) 62 } 63 } 64 65 return strings.Join(out, "\n") 66 } 67 68 // Raw returns a slice of interfaces containing the raw form of all 69 // the constituent composers. 70 func (g *GroupComposer) Raw() interface{} { 71 g.mutex.RLock() 72 defer g.mutex.RUnlock() 73 74 if len(g.messages) == 1 && g.messages[0].Loggable() { 75 return g.messages[0].Raw() 76 } 77 78 out := []interface{}{} 79 for _, m := range g.messages { 80 if m == nil { 81 continue 82 } 83 if m.Loggable() { 84 out = append(out, m.Raw()) 85 } 86 } 87 88 return out 89 } 90 91 // Loggable returns true if at least one of the constituent Composers 92 // is loggable. 93 func (g *GroupComposer) Loggable() bool { 94 g.mutex.RLock() 95 defer g.mutex.RUnlock() 96 97 for _, m := range g.messages { 98 if m == nil { 99 continue 100 } 101 if m.Loggable() { 102 return true 103 } 104 } 105 106 return false 107 } 108 109 // Priority returns the highest priority of the constituent Composers. 110 func (g *GroupComposer) Priority() level.Priority { 111 var highest level.Priority 112 113 g.mutex.RLock() 114 defer g.mutex.RUnlock() 115 116 for _, m := range g.messages { 117 if m == nil { 118 continue 119 } 120 pri := m.Priority() 121 if pri > highest { 122 highest = pri 123 } 124 } 125 126 return highest 127 } 128 129 // SetPriority sets the priority of all constituent Composers *only* 130 // if the existing level is unset, and does not propagate an error, 131 // but will *not* unset the level of the compser and will return an error 132 // in this case. 133 func (g *GroupComposer) SetPriority(l level.Priority) error { 134 if l == level.Invalid { 135 return fmt.Errorf("cannot set priority to an invalid setting") 136 } 137 138 g.mutex.RLock() 139 defer g.mutex.RUnlock() 140 141 for _, m := range g.messages { 142 if m == nil { 143 continue 144 } 145 146 if m.Priority() == level.Invalid { 147 _ = m.SetPriority(l) 148 } 149 } 150 151 return nil 152 } 153 154 // Messages returns a the underlying collection of messages. 155 func (g *GroupComposer) Messages() []Composer { 156 g.mutex.RLock() 157 defer g.mutex.RUnlock() 158 159 return g.messages 160 } 161 162 // Add supports adding messages to an existing group composer. 163 func (g *GroupComposer) Add(msg Composer) { 164 g.mutex.Lock() 165 defer g.mutex.Unlock() 166 167 g.messages = append(g.messages, msg) 168 } 169 170 // Extend makes it possible to add a group of messages to an existing 171 // group composer. 172 func (g *GroupComposer) Extend(msg []Composer) { 173 g.mutex.Lock() 174 defer g.mutex.Unlock() 175 176 g.messages = append(g.messages, msg...) 177 } 178 179 // Append provides a variadic alternative to the Extend method. 180 func (g *GroupComposer) Append(msgs ...Composer) { 181 g.Extend(msgs) 182 } 183 184 // Annotate calls the Annotate method of every non-nil component 185 // Composer. 186 func (g *GroupComposer) Annotate(k string, v interface{}) error { 187 g.mutex.Lock() 188 defer g.mutex.Unlock() 189 190 for _, m := range g.messages { 191 if m == nil { 192 continue 193 } 194 195 _ = m.Annotate(k, v) 196 } 197 198 return nil 199 }