| @@ -0,0 +1,262 @@ | ||
| package logger | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
| "io" | ||
| "reflect" | ||
| "os" | ||
| ) | ||
|
|
||
| var INFO_STRUCT_TYPE = structType(Info{}) | ||
| var WARN_STRUCT_TYPE = structType(Warn{}) | ||
| var ERROR_STRUCT_TYPE = structType(Error{}) | ||
|
|
||
| var INFO_TYPE = reflect.TypeOf(Info{}) | ||
| var WARN_TYPE = reflect.TypeOf(Warn{}) | ||
| var ERROR_TYPE = reflect.TypeOf(Error{}) | ||
|
|
||
|
|
||
| /* This file dedicated to parsing the logs written by a JsonLogger */ | ||
|
|
||
| type Parse interface { | ||
| ExtractLog(receive chan ParsedLog) ParsedLog | ||
| ExtractLogs() []ParsedLog | ||
| } | ||
|
|
||
|
|
||
| type Parser struct { | ||
| decoders []*json.Decoder | ||
| extractNew chan ExtractRequest | ||
| quit chan bool | ||
| } | ||
|
|
||
| type ParsedLog struct { | ||
| Log interface{} | ||
| Err error | ||
| } | ||
|
|
||
| type ExtractRequest struct { | ||
| ReaderNum int | ||
| LogChan chan ParsedLog | ||
| } | ||
|
|
||
| // Given an io.Reader, which is pointing to where your logs are written to | ||
| // A new Parser is created around the reader | ||
| func NewParser(readers ...io.Reader) *Parser { | ||
|
|
||
| extractNewLog, quit := make(chan ExtractRequest), make(chan bool) | ||
|
|
||
| var decoders []*json.Decoder | ||
|
|
||
| for _, r := range readers { | ||
| decoders = append(decoders, json.NewDecoder(r)) | ||
| } | ||
|
|
||
| parser := &Parser{decoders, extractNewLog, quit} | ||
|
|
||
| go parser.extract() | ||
|
|
||
| return parser | ||
|
|
||
| } | ||
|
|
||
| func (parser *Parser) extract() { | ||
| for { | ||
| select { | ||
|
|
||
| case <-parser.quit: | ||
| break | ||
|
|
||
| case requestChan := <-parser.extractNew: | ||
|
|
||
| var logVal map[string]interface{} | ||
|
|
||
| err := parser.decoders[requestChan.ReaderNum - 1].Decode(&logVal) | ||
|
|
||
| requestChan.LogChan <- ParsedLog{convert(logVal), err} | ||
|
|
||
| } | ||
| } | ||
| } | ||
|
|
||
| // This decodes exactly one log from the provided reader | ||
| // What ever happens to be the first one | ||
| func (parser *Parser) ExtractLog(receive ExtractRequest) ParsedLog { | ||
|
|
||
| go func() { parser.extractNew <- receive }() | ||
|
|
||
| return <-receive.LogChan | ||
|
|
||
| } | ||
|
|
||
| // This decodes all logs from the provided reader | ||
| func (parser *Parser) ExtractLogs() []ParsedLog { | ||
|
|
||
| var logs []ParsedLog | ||
| var log ParsedLog | ||
|
|
||
| receiveLogChan := make(chan ParsedLog) | ||
| receiveRequest := ExtractRequest{1, receiveLogChan} | ||
|
|
||
| for parser.decoders[receiveRequest.ReaderNum - 1].More() { | ||
|
|
||
| log = parser.ExtractLog(receiveRequest) | ||
|
|
||
| if log.Err != nil { | ||
| return logs | ||
| } | ||
|
|
||
| logs = append(logs, log) | ||
|
|
||
| } | ||
|
|
||
| return logs | ||
|
|
||
| } | ||
|
|
||
| func (parser *Parser) Close() { | ||
| parser.quit <- true | ||
| } | ||
|
|
||
|
|
||
| // This is simply a helper function for printing logs out to Stdout | ||
| // in a pretty printed JSON format i.e. it has indentation | ||
| func PrettyPrint(logs ...interface{}) { | ||
|
|
||
| encoder := json.NewEncoder(os.Stdout) | ||
| encoder.SetIndent("", " ") | ||
|
|
||
| for _, log := range logs { | ||
| if err := encoder.Encode(&log); err != nil { | ||
| panic(err) | ||
| } | ||
| } | ||
|
|
||
| } | ||
|
|
||
|
|
||
| // This is a helper function for converting the decoded map into | ||
| // a log struct | ||
| func convert(logInterface map[string]interface{}) interface{} { | ||
|
|
||
| var structFields []reflect.StructField | ||
| var fieldType reflect.Type | ||
| var warnLevelType int | ||
|
|
||
| for field, val := range logInterface { | ||
|
|
||
| fieldType = reflect.TypeOf(val) | ||
|
|
||
| if fieldType.Kind() == reflect.Float64 { | ||
| fieldType = reflect.TypeOf(warnLevelType) | ||
| } | ||
|
|
||
| structFields = append(structFields, reflect.StructField{Name: field, Type: fieldType}) | ||
| } | ||
|
|
||
| logStruct := reflect.New(reflect.StructOf(structFields)).Elem() | ||
|
|
||
| var infoFields, warnFields, errorFields int | ||
|
|
||
| for i := 0; i < logStruct.NumField(); i++ { | ||
| f := logStruct.Type().Field(i) | ||
|
|
||
| switch { | ||
| case containsField(INFO_STRUCT_TYPE, f): | ||
| infoFields++ | ||
| case containsField(WARN_STRUCT_TYPE, f): | ||
| warnFields++ | ||
| case containsField(ERROR_STRUCT_TYPE, f): | ||
| errorFields++ | ||
| } | ||
| } | ||
|
|
||
| var newLogStruct reflect.Value | ||
| var newLogStructFields []reflect.StructField | ||
| var specificLogStruct interface{} | ||
|
|
||
| switch { | ||
|
|
||
| case infoFields | errorFields == 5: | ||
| newLogStructFields = reArrangStructFields(ERROR_STRUCT_TYPE, logStruct) | ||
|
|
||
| newLogStruct = reflect.New(reflect.StructOf(newLogStructFields)).Elem() | ||
|
|
||
| setStructVals(logInterface, newLogStruct) | ||
|
|
||
| specificLogStruct = newLogStruct.Convert(ERROR_TYPE).Interface() | ||
|
|
||
| case infoFields | warnFields == 5: | ||
| newLogStructFields = reArrangStructFields(WARN_STRUCT_TYPE, logStruct) | ||
|
|
||
| newLogStruct = reflect.New(reflect.StructOf(newLogStructFields)).Elem() | ||
|
|
||
| setStructVals(logInterface, newLogStruct) | ||
|
|
||
| specificLogStruct = newLogStruct.Convert(WARN_TYPE).Interface() | ||
|
|
||
| default: | ||
| newLogStructFields = reArrangStructFields(INFO_STRUCT_TYPE, logStruct) | ||
|
|
||
| newLogStruct = reflect.New(reflect.StructOf(newLogStructFields)).Elem() | ||
|
|
||
| setStructVals(logInterface, newLogStruct) | ||
|
|
||
| specificLogStruct = newLogStruct.Convert(INFO_TYPE).Interface() | ||
| } | ||
|
|
||
| return specificLogStruct | ||
|
|
||
| } | ||
|
|
||
|
|
||
| // Helper function for checking if a struct contains a field or not | ||
| func containsField(structType reflect.Type, field reflect.StructField) bool { | ||
| _, ok := structType.FieldByName(field.Name) | ||
| return ok | ||
| } | ||
|
|
||
|
|
||
| func reArrangStructFields(structType reflect.Type, oldStruct reflect.Value) []reflect.StructField { | ||
| var newLogStructFields []reflect.StructField | ||
|
|
||
| for j := 0; j < structType.NumField(); j++ { | ||
| structField, _ := oldStruct.Type().FieldByName( structType.Field(j).Name ) | ||
| newLogStructFields = append(newLogStructFields, structField) | ||
| } | ||
|
|
||
| return newLogStructFields | ||
| } | ||
|
|
||
|
|
||
| func setStructVals(structFields map[string]interface{}, logStruct reflect.Value) { | ||
| var warnLevelType int | ||
|
|
||
| for field, val := range structFields { | ||
|
|
||
| valVal := reflect.ValueOf(val) | ||
|
|
||
| if valVal.Kind() == reflect.Float64 { | ||
| valVal = valVal.Convert(reflect.TypeOf(warnLevelType)) | ||
| } | ||
|
|
||
| logStruct.FieldByName(field).Set( valVal ) | ||
| } | ||
| } | ||
|
|
||
| // This is merely a helper funtion for declaring const values | ||
| func structType(logType interface{}) reflect.Type { | ||
|
|
||
| var structFields []reflect.StructField | ||
|
|
||
| logStructType := reflect.TypeOf(logType) | ||
|
|
||
| for i := 0; i < logStructType.NumField(); i++ { | ||
| structFields = append(structFields, logStructType.Field(i)) | ||
| } | ||
|
|
||
| logStruct := reflect.New(reflect.StructOf(structFields)).Elem() | ||
|
|
||
| return logStruct.Type() | ||
|
|
||
| } |
| @@ -0,0 +1,60 @@ | ||
| { | ||
| "Type": "INFO", | ||
| "Time": "2017-09-10 19:34:55.379968747 -0400 EDT", | ||
| "Message": "INFO test", | ||
| "Stack": "logger.(*JsonLogger).Info(0xc42001b0b0, 0x59d44e, 0x9)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/log.go:86 +0x5e\nlogger.TestJsonLogger_Info(0xc42005e8f0)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/logger_test.go:36 +0x42\ntesting.tRunner(0xc42005e8f0, 0x5a7440)\n\t/usr/lib/go-1.8/src/testing/testing.go:657 +0x96\ncreated by testing.(*T).Run\n\t/usr/lib/go-1.8/src/testing/testing.go:697 +0x2ca\n" | ||
| } | ||
| { | ||
| "Type": "WARN", | ||
| "Time": "2017-09-10 19:34:57.380293825 -0400 EDT", | ||
| "Level": 3, | ||
| "Message": "WARN test", | ||
| "Stack": "logger.(*JsonLogger).Warn(0xc42001b0b0, 0x3, 0x59d51d, 0x9)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/log.go:92 +0x5e\nlogger.TestJsonLogger_Warn(0xc4200c6000)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/logger_test.go:44 +0x4b\ntesting.tRunner(0xc4200c6000, 0x5a7448)\n\t/usr/lib/go-1.8/src/testing/testing.go:657 +0x96\ncreated by testing.(*T).Run\n\t/usr/lib/go-1.8/src/testing/testing.go:697 +0x2ca\n" | ||
| } | ||
| { | ||
| "Type": "ERROR", | ||
| "Time": "2017-09-10 19:34:59.380605737 -0400 EDT", | ||
| "Message": "ERROR test", | ||
| "Error": "New error for testing", | ||
| "Stack": "logger.(*JsonLogger).Error(0xc42001b0b0, 0x6505c0, 0xc4200ec170, 0x59d8b9, 0xa)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/log.go:98 +0x8c\nlogger.TestJsonLogger_Error(0xc4200f60d0)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/logger_test.go:52 +0x8d\ntesting.tRunner(0xc4200f60d0, 0x5a7438)\n\t/usr/lib/go-1.8/src/testing/testing.go:657 +0x96\ncreated by testing.(*T).Run\n\t/usr/lib/go-1.8/src/testing/testing.go:697 +0x2ca\n" | ||
| } | ||
| { | ||
| "Type": "INFO", | ||
| "Time": "2017-09-10 19:35:31.555179616 -0400 EDT", | ||
| "Message": "INFO test", | ||
| "Stack": "logger.(*JsonLogger).Info(0xc42001b0b0, 0x59d44e, 0x9)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/log.go:86 +0x5e\nlogger.TestJsonLogger_Info(0xc42005f040)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/logger_test.go:87 +0x42\ntesting.tRunner(0xc42005f040, 0x5a7440)\n\t/usr/lib/go-1.8/src/testing/testing.go:657 +0x96\ncreated by testing.(*T).Run\n\t/usr/lib/go-1.8/src/testing/testing.go:697 +0x2ca\n" | ||
| } | ||
| { | ||
| "Type": "WARN", | ||
| "Time": "2017-09-10 19:35:33.555439849 -0400 EDT", | ||
| "Level": 3, | ||
| "Message": "WARN test", | ||
| "Stack": "logger.(*JsonLogger).Warn(0xc42001b0b0, 0x3, 0x59d51d, 0x9)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/log.go:92 +0x5e\nlogger.TestJsonLogger_Warn(0xc4200d21a0)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/logger_test.go:95 +0x4b\ntesting.tRunner(0xc4200d21a0, 0x5a7448)\n\t/usr/lib/go-1.8/src/testing/testing.go:657 +0x96\ncreated by testing.(*T).Run\n\t/usr/lib/go-1.8/src/testing/testing.go:697 +0x2ca\n" | ||
| } | ||
| { | ||
| "Type": "ERROR", | ||
| "Time": "2017-09-10 19:35:35.555748373 -0400 EDT", | ||
| "Message": "ERROR test", | ||
| "Error": "New error for testing", | ||
| "Stack": "logger.(*JsonLogger).Error(0xc42001b0b0, 0x6505c0, 0xc42010c170, 0x59d8b9, 0xa)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/log.go:98 +0x8c\nlogger.TestJsonLogger_Error(0xc4201160d0)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/logger_test.go:103 +0x8d\ntesting.tRunner(0xc4201160d0, 0x5a7438)\n\t/usr/lib/go-1.8/src/testing/testing.go:657 +0x96\ncreated by testing.(*T).Run\n\t/usr/lib/go-1.8/src/testing/testing.go:697 +0x2ca\n" | ||
| } | ||
| { | ||
| "Type": "INFO", | ||
| "Time": "2017-09-10 19:36:48.263463163 -0400 EDT", | ||
| "Message": "INFO test", | ||
| "Stack": "logger.(*JsonLogger).Info(0xc42001b0b0, 0x59d44e, 0x9)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/log.go:86 +0x5e\nlogger.TestJsonLogger_Info(0xc42005f790)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/logger_test.go:87 +0x42\ntesting.tRunner(0xc42005f790, 0x5a7440)\n\t/usr/lib/go-1.8/src/testing/testing.go:657 +0x96\ncreated by testing.(*T).Run\n\t/usr/lib/go-1.8/src/testing/testing.go:697 +0x2ca\n" | ||
| } | ||
| { | ||
| "Type": "WARN", | ||
| "Time": "2017-09-10 19:36:50.263781237 -0400 EDT", | ||
| "Level": 3, | ||
| "Message": "WARN test", | ||
| "Stack": "logger.(*JsonLogger).Warn(0xc42001b0b0, 0x3, 0x59d51d, 0x9)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/log.go:92 +0x5e\nlogger.TestJsonLogger_Warn(0xc4200d0000)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/logger_test.go:95 +0x4b\ntesting.tRunner(0xc4200d0000, 0x5a7448)\n\t/usr/lib/go-1.8/src/testing/testing.go:657 +0x96\ncreated by testing.(*T).Run\n\t/usr/lib/go-1.8/src/testing/testing.go:697 +0x2ca\n" | ||
| } | ||
| { | ||
| "Type": "ERROR", | ||
| "Time": "2017-09-10 19:36:52.264083769 -0400 EDT", | ||
| "Message": "ERROR test", | ||
| "Error": "New error for testing", | ||
| "Stack": "logger.(*JsonLogger).Error(0xc42001b0b0, 0x6505c0, 0xc4200f80a0, 0x59d8b9, 0xa)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/log.go:98 +0x8c\nlogger.TestJsonLogger_Error(0xc420108000)\n\t/home/carson/Desktop/Go/GogoAnimeApi/src/logger/logger_test.go:103 +0x8d\ntesting.tRunner(0xc420108000, 0x5a7438)\n\t/usr/lib/go-1.8/src/testing/testing.go:657 +0x96\ncreated by testing.(*T).Run\n\t/usr/lib/go-1.8/src/testing/testing.go:697 +0x2ca\n" | ||
| } |
| @@ -0,0 +1 @@ | ||
| package connection |
| @@ -0,0 +1 @@ | ||
| package query |