github.com/abolfazlbeh/zhycan@v0.0.0-20230819144214-24cf38237387/internal/logger/zhycan_wrapper.go (about) 1 package logger 2 3 // Imports needed list 4 import ( 5 "encoding/json" 6 "github.com/abolfazlbeh/zhycan/internal/config" 7 "github.com/abolfazlbeh/zhycan/internal/utils" 8 "log" 9 "os" 10 "sync" 11 "time" 12 ) 13 14 type OutputOption struct { 15 LevelStr string `json:"level"` 16 Level LogLevel `json:"-"` 17 Path string `json:"path,omitempty"` 18 l *log.Logger `json:"-"` 19 } 20 21 // MARK: LogMeWrapper 22 23 // LogMeWrapper structure - implements Logger interface 24 type LogMeWrapper struct { 25 name string 26 serviceName string 27 ch chan LogObject 28 initialized bool 29 wg sync.WaitGroup 30 operationType string 31 supportedOutput []string 32 supportedOutputOption map[string]OutputOption 33 } 34 35 // Constructor - It initializes the logger configuration params 36 func (l *LogMeWrapper) Constructor(name string) error { 37 l.wg.Add(1) 38 defer l.wg.Done() 39 40 l.name = name 41 l.serviceName = config.GetManager().GetName() 42 l.operationType = config.GetManager().GetOperationType() 43 l.supportedOutput = []string{"console", "file"} 44 l.initialized = false 45 46 channelSize, err := config.GetManager().Get(l.name, "channel_size") 47 if err != nil { 48 return err 49 } 50 51 options, err := config.GetManager().Get(l.name, "options") 52 if err != nil { 53 return err 54 } 55 56 optionArray := make([]string, len(options.([]interface{}))) 57 for _, v := range options.([]interface{}) { 58 optionArray = append(optionArray, v.(string)) 59 } 60 61 outputs, err := config.GetManager().Get(l.name, "outputs") 62 if err != nil { 63 return err 64 } 65 66 var outputArray []string 67 for _, v := range outputs.([]interface{}) { 68 outputArray = append(outputArray, v.(string)) 69 } 70 71 l.ch = make(chan LogObject, int(channelSize.(float64))) 72 73 //if l.operationType == "prod" { 74 //} else { 75 //} 76 l.supportedOutputOption = make(map[string]OutputOption) 77 for _, item := range outputArray { 78 if utils.ArrayContains(&l.supportedOutput, item) { 79 jsonObj, configReadErr := config.GetManager().Get(l.name, item) 80 if configReadErr == nil { 81 r := OutputOption{} 82 83 jsonStr, jsonErr := json.Marshal(jsonObj.(map[string]interface{})) 84 if jsonErr == nil { 85 jsonErr = json.Unmarshal(jsonStr, &r) 86 if jsonErr == nil { 87 // add it to internal map 88 r.Level = StringToLogLevel(r.LevelStr) 89 if item == "console" { 90 r.l = log.New(os.Stdout, "", 0) 91 } 92 l.supportedOutputOption[item] = r 93 94 // run the instance ... 95 go l.runner(item) 96 } else { 97 log.Printf("Cannot create log instance for: %v - %v", item, jsonErr) 98 } 99 } else { 100 log.Printf("Cannot create log instance for: %v - %v", item, jsonErr) 101 } 102 } else { 103 log.Printf("Cannot create log instance for: %v - %v", item, configReadErr) 104 } 105 } else { 106 log.Printf("Log outout with name `%v` is not supported yet", item) 107 } 108 } 109 110 l.initialized = true 111 112 return nil 113 } 114 115 // IsInitialized - that returns boolean value whether it's initialized 116 func (l *LogMeWrapper) IsInitialized() bool { 117 return l.initialized 118 } 119 120 // Log - write log object to the channel 121 func (l *LogMeWrapper) Log(obj *LogObject) { 122 l.wg.Wait() 123 124 go func(obj *LogObject) { 125 l.ch <- *obj 126 }(obj) 127 } 128 129 // Sync - sync all logs to medium 130 func (l *LogMeWrapper) Sync() { 131 l.wg.Wait() 132 ch := make(chan bool, 1) 133 go func() { 134 for { 135 if len(l.ch) > 0 { 136 time.Sleep(time.Millisecond * 200) 137 } else { 138 ch <- true 139 } 140 } 141 }() 142 143 <-ch 144 } 145 146 // Close - it closes logger channel 147 func (l *LogMeWrapper) Close() { 148 l.wg.Wait() 149 l.Sync() 150 defer close(l.ch) 151 } 152 153 // runner - the goroutine that reads from channel and process it 154 func (l *LogMeWrapper) runner(output string) { 155 l.wg.Wait() 156 for c := range l.ch { 157 if c.Level <= l.supportedOutputOption[output].Level { 158 switch c.Level { 159 case DEBUG: 160 l.debug(&c, output) 161 case INFO: 162 l.info(&c, output) 163 case WARNING: 164 l.info(&c, output) 165 case ERROR: 166 l.info(&c, output) 167 } 168 } 169 } 170 } 171 172 // debug - log with DEBUG level 173 func (l *LogMeWrapper) debug(object *LogObject, output string) { 174 if output == "console" { 175 l.supportedOutputOption[output].l.Printf( 176 "\\e[37m%v %v >>> %7v >>> (%v/%v) - %v ... %v\\e[0m\n", 177 l.serviceName, 178 object.Time, 179 object.Level.String(), 180 object.LogType, 181 object.Module, 182 object.Module, 183 object.Additional, 184 ) 185 } 186 } 187 188 // info - log with INFO level 189 func (l *LogMeWrapper) info(object *LogObject, output string) { 190 if output == "console" { 191 l.supportedOutputOption[output].l.Printf( 192 "\\e[32m%v %v >>> %7v >>> (%v/%v) - %v ... %v\\e[0m\n", 193 l.serviceName, 194 object.Time, 195 object.Level.String(), 196 object.LogType, 197 object.Module, 198 object.Module, 199 object.Additional, 200 ) 201 } 202 } 203 204 // warning - log with WARNING level 205 func (l *LogMeWrapper) warning(object *LogObject, output string) { 206 if output == "console" { 207 l.supportedOutputOption[output].l.Printf( 208 "\\e[33m%v %v >>> %7v >>> (%v/%v) - %v ... %v\\e[0m\n", 209 l.serviceName, 210 object.Time, 211 object.Level.String(), 212 object.LogType, 213 object.Module, 214 object.Module, 215 object.Additional, 216 ) 217 } 218 } 219 220 // error - log with ERROR level 221 func (l *LogMeWrapper) error(object *LogObject, output string) { 222 if output == "console" { 223 l.supportedOutputOption[output].l.Printf( 224 "\\e[31m%v %v >>> %7v >>> (%v/%v) - %v ... %v\\e[0m\n", 225 l.serviceName, 226 object.Time, 227 object.Level.String(), 228 object.LogType, 229 object.Module, 230 object.Module, 231 object.Additional, 232 ) 233 } 234 }