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  }