storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/consolelogger.go (about) 1 /* 2 * MinIO Cloud Storage, (C) 2019 MinIO, Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cmd 18 19 import ( 20 ring "container/ring" 21 "context" 22 "sync" 23 24 "storj.io/minio/cmd/logger" 25 "storj.io/minio/cmd/logger/message/log" 26 "storj.io/minio/cmd/logger/target/console" 27 xnet "storj.io/minio/pkg/net" 28 "storj.io/minio/pkg/pubsub" 29 ) 30 31 // number of log messages to buffer 32 const defaultLogBufferCount = 10000 33 34 //HTTPConsoleLoggerSys holds global console logger state 35 type HTTPConsoleLoggerSys struct { 36 sync.RWMutex 37 pubsub *pubsub.PubSub 38 console *console.Target 39 nodeName string 40 logBuf *ring.Ring 41 } 42 43 // NewConsoleLogger - creates new HTTPConsoleLoggerSys with all nodes subscribed to 44 // the console logging pub sub system 45 func NewConsoleLogger(ctx context.Context) *HTTPConsoleLoggerSys { 46 ps := pubsub.New() 47 return &HTTPConsoleLoggerSys{ 48 pubsub: ps, 49 console: console.New(), 50 logBuf: ring.New(defaultLogBufferCount), 51 } 52 } 53 54 // SetNodeName - sets the node name if any after distributed setup has initialized 55 func (sys *HTTPConsoleLoggerSys) SetNodeName(nodeName string) { 56 if !globalIsDistErasure { 57 sys.nodeName = "" 58 return 59 } 60 61 host, err := xnet.ParseHost(globalLocalNodeName) 62 if err != nil { 63 logger.FatalIf(err, "Unable to start console logging subsystem") 64 } 65 66 sys.nodeName = host.Name 67 } 68 69 // HasLogListeners returns true if console log listeners are registered 70 // for this node or peers 71 func (sys *HTTPConsoleLoggerSys) HasLogListeners() bool { 72 return sys != nil && sys.pubsub.NumSubscribers() > 0 73 } 74 75 // Subscribe starts console logging for this node. 76 func (sys *HTTPConsoleLoggerSys) Subscribe(subCh chan interface{}, doneCh <-chan struct{}, node string, last int, logKind string, filter func(entry interface{}) bool) { 77 // Enable console logging for remote client. 78 if !sys.HasLogListeners() { 79 logger.AddTarget(sys) 80 } 81 82 cnt := 0 83 // by default send all console logs in the ring buffer unless node or limit query parameters 84 // are set. 85 var lastN []log.Info 86 if last > defaultLogBufferCount || last <= 0 { 87 last = defaultLogBufferCount 88 } 89 90 lastN = make([]log.Info, last) 91 sys.RLock() 92 sys.logBuf.Do(func(p interface{}) { 93 if p != nil { 94 lg, ok := p.(log.Info) 95 if ok && lg.SendLog(node, logKind) { 96 lastN[cnt%last] = lg 97 cnt++ 98 } 99 } 100 }) 101 sys.RUnlock() 102 // send last n console log messages in order filtered by node 103 if cnt > 0 { 104 for i := 0; i < last; i++ { 105 entry := lastN[(cnt+i)%last] 106 if (entry == log.Info{}) { 107 continue 108 } 109 select { 110 case subCh <- entry: 111 case <-doneCh: 112 return 113 } 114 } 115 } 116 sys.pubsub.Subscribe(subCh, doneCh, filter) 117 } 118 119 // Validate if HTTPConsoleLoggerSys is valid, always returns nil right now 120 func (sys *HTTPConsoleLoggerSys) Validate() error { 121 return nil 122 } 123 124 // Endpoint - dummy function for interface compatibility 125 func (sys *HTTPConsoleLoggerSys) Endpoint() string { 126 return sys.console.Endpoint() 127 } 128 129 // String - stringer function for interface compatibility 130 func (sys *HTTPConsoleLoggerSys) String() string { 131 return "console+http" 132 } 133 134 // Content returns the console stdout log 135 func (sys *HTTPConsoleLoggerSys) Content() (logs []log.Entry) { 136 sys.RLock() 137 sys.logBuf.Do(func(p interface{}) { 138 if p != nil { 139 lg, ok := p.(log.Info) 140 if ok { 141 if (lg.Entry != log.Entry{}) { 142 logs = append(logs, lg.Entry) 143 } 144 } 145 } 146 }) 147 sys.RUnlock() 148 149 return 150 } 151 152 // Send log message 'e' to console and publish to console 153 // log pubsub system 154 func (sys *HTTPConsoleLoggerSys) Send(e interface{}, logKind string) error { 155 var lg log.Info 156 switch e := e.(type) { 157 case log.Entry: 158 lg = log.Info{Entry: e, NodeName: sys.nodeName} 159 case string: 160 lg = log.Info{ConsoleMsg: e, NodeName: sys.nodeName} 161 } 162 163 sys.pubsub.Publish(lg) 164 sys.Lock() 165 // add log to ring buffer 166 sys.logBuf.Value = lg 167 sys.logBuf = sys.logBuf.Next() 168 sys.Unlock() 169 170 return sys.console.Send(e, string(logger.All)) 171 }