diff --git a/gologger/http_logs.go b/gologger/http_logs.go deleted file mode 100644 index 06589aa..0000000 --- a/gologger/http_logs.go +++ /dev/null @@ -1,66 +0,0 @@ -package gologger - -import ( - "bytes" - "fmt" - "net/http" - "net/http/httputil" - "os" - "strings" - "time" -) - -const splitLine = "==============================================================" - -// LogHTTPRequest ... -func (l *Logger) LogHTTPRequest(req *http.Request, userID string) string { - if userID == "" { - userID = "-" - } - - var b strings.Builder - - b.WriteString("Request:\n") - // CLF-like header - fmt.Fprintf(&b, "%s %s %s\n", req.RemoteAddr, userID, time.Now().Format(dateTimeFormat)) - - body, err := httputil.DumpRequest(req, true) - if err != nil { - fmt.Fprintf(os.Stderr, "%v\n", err) - } - - const sepStr = "\r\n\r\n" - sepIndex := bytes.Index(body, []byte(sepStr)) - if sepIndex == -1 { - b.WriteString(string(body) + "\n\n") - } else { - sepIndex += len(sepStr) - payload, _ := printJSON(body[sepIndex:]) - b.WriteString(string(body[:sepIndex]) + string(payload) + "\n\n") - } - - return b.String() -} - -// LogHTTPResponse ... -func (l *Logger) LogHTTPResponse(data []byte, status int, startTime time.Time) string { - duration := time.Now().Sub(startTime) - jsonData, _ := printJSON(data) - return fmt.Sprintf("Response:\n%d %v %dB\n%s\n%s\n\n", status, duration, len(data), jsonData, splitLine) -} - -// CombineHTTPLogs ... -func (l *Logger) CombineHTTPLogs(in string, out string) { - if l.outputFile == nil { - return - } - - l.mu.Lock() - defer l.mu.Unlock() - - msg := in + out - if l.shouldSplit(len(msg)) { - l.split() - } - l.outputFile.WriteString(msg) -} diff --git a/gologger/main.go b/gologger/main.go deleted file mode 100644 index 5f731eb..0000000 --- a/gologger/main.go +++ /dev/null @@ -1,162 +0,0 @@ -package gologger - -import ( - "bytes" - "encoding/json" - "fmt" - "os" - "path/filepath" - "strings" - "sync" - "time" -) - -const dateTimeFormat = "2006-01-02 15:04:05" - -// Block ... -const ( - MaxLogSize5MB int64 = 5 * 1024 * 1024 - MaxLogSize1MB int64 = 1 * 1024 * 1024 - MaxLogSize500KB int64 = 500 * 1024 - MaxLogSize100KB int64 = 100 * 1024 - MaxLogSize512B int64 = 512 -) - -// Logger ... -type Logger struct { - mu *sync.Mutex - outputFile *os.File - - outputFileName string - fullName string - maxFileSize int64 - - splitCount int - - directory string -} - -// New ... -func New(name, dir string, maxFileSize int64) (logger *Logger, err error) { - logger = &Logger{} - - logger.outputFileName = name - logger.mu = &sync.Mutex{} - logger.maxFileSize = maxFileSize - logger.directory = dir - - err = os.Mkdir(dir, os.ModePerm) - if err != nil { - if !os.IsExist(err) { - return nil, err - } - } - - date := strings.Replace(time.Now().Format(dateTimeFormat), ":", ".", -1) - logger.outputFileName += " " + date - logger.fullName = logger.outputFileName + ".txt" - path := filepath.Join(dir, logger.fullName) - if logger.outputFile, err = os.Create(path); err != nil { - return nil, err - } - - return logger, nil -} - -// Log ... -func (l *Logger) Log(format string, v ...interface{}) { - if l.outputFile == nil { - return - } - - l.mu.Lock() - defer l.mu.Unlock() - - msg := fmt.Sprintf(format, v...) - s := time.Now().Format(dateTimeFormat) + ": " + msg + "\n" - if l.shouldSplit(len(s)) { - l.split() - } - l.outputFile.WriteString(s) -} - -// Print ... -func (l *Logger) Print(format string, v ...interface{}) { - msg := fmt.Sprintf(format, v...) - fmt.Printf("%s: %s\n", time.Now().Format(dateTimeFormat), msg) -} - -// Trace ... -func (l *Logger) Trace(format string, v ...interface{}) string { - if l.outputFile == nil { - return "" - } - - l.mu.Lock() - defer l.mu.Unlock() - - s := getTrace(format, v...) + "\n" - - if l.shouldSplit(len(s)) { - l.split() - } - l.outputFile.WriteString(s) - - return s -} - -// PrintTrace ... -func (l *Logger) PrintTrace(format string, v ...interface{}) { - s := getTrace(format, v...) - fmt.Printf("%s\n", s) -} - -// PrintAndTrace ... -func (l *Logger) PrintAndTrace(format string, v ...interface{}) { - t := l.Trace(format, v...) - fmt.Println(t) -} - -// Close ... -func (l *Logger) Close() error { - if l.outputFile == nil { - return nil - } - - return l.outputFile.Close() -} - -func (l *Logger) split() error { - if l.outputFile == nil { - return nil - } - - // close old file - err := l.outputFile.Close() - if err != nil { - return err - } - - // open new file - l.splitCount++ - path := filepath.Join(l.directory, l.outputFileName+fmt.Sprintf("(%d)", l.splitCount)+".txt") - l.outputFile, err = os.Create(path) - - return err -} - -func (l *Logger) shouldSplit(nextEntrySize int) bool { - stats, _ := l.outputFile.Stat() - return int64(nextEntrySize) >= (l.maxFileSize - stats.Size()) -} - -func printJSON(in []byte) (out []byte, err error) { - var buf bytes.Buffer - err = json.Indent(&buf, in, "", " ") - return buf.Bytes(), err -} - -// GetOutDir ... -func (l *Logger) GetOutDir() string { - return l.directory -} diff --git a/gologger/tracing.go b/gologger/tracing.go deleted file mode 100644 index 28a6477..0000000 --- a/gologger/tracing.go +++ /dev/null @@ -1,65 +0,0 @@ -package gologger - -import ( - "fmt" - "math" - "runtime" - "strings" - "time" -) - -// getCallStack -func getCallStack() (stack []string) { - const ( - maxStackDepth = 10000 - skipRuntime = 2 // skip runtime and startup - skipCallers = 2 - thisPackage = "gologger" - ) - - callers := make([]uintptr, maxStackDepth) // min 1 - - stackDepth := runtime.Callers(skipCallers, callers) - frames := runtime.CallersFrames(callers) - - for i := 0; i < skipRuntime; i++ { - frames.Next() - } - - for i := 0; i < stackDepth-skipRuntime-skipCallers; i++ { - frame, next := frames.Next() - if !strings.Contains(frame.File, thisPackage) { - stack = append(stack, fmt.Sprintf("[%s %d]", frame.File, frame.Line)) - } - if !next { - break - } - } - - reverseStack(stack) - - return stack -} - -// in place -func reverseStack(stack []string) { - middle := int(math.Floor(float64(len(stack)) / 2.0)) - - lastIndex := len(stack) - 1 - for i := 0; i < middle; i++ { - stack[i], stack[lastIndex] = stack[lastIndex], stack[i] - lastIndex-- - } -} - -func getTrace(format string, v ...interface{}) (t string) { - stack := getCallStack() - - t = time.Now().Format(dateTimeFormat) + ":\n" - for _, s := range stack { - t += s + "\n" - } - t += fmt.Sprintf(format, v...) + "\n" - - return t -} diff --git a/logger/http_logs.go b/logger/http_logs.go new file mode 100644 index 0000000..3bd9174 --- /dev/null +++ b/logger/http_logs.go @@ -0,0 +1,66 @@ +package logger + +import ( + "bytes" + "fmt" + "net/http" + "net/http/httputil" + "os" + "strings" + "time" +) + +const splitLine = "==============================================================" + +// LogHTTPRequest ... +func (l *Logger) LogHTTPRequest(req *http.Request, userID string) string { + if userID == "" { + userID = "-" + } + + var b strings.Builder + + b.WriteString("Request:\n") + // CLF-like header + fmt.Fprintf(&b, "%s %s %s\n", req.RemoteAddr, userID, time.Now().Format(dateTimeFormat)) + + body, err := httputil.DumpRequest(req, true) + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + } + + const sepStr = "\r\n\r\n" + sepIndex := bytes.Index(body, []byte(sepStr)) + if sepIndex == -1 { + b.WriteString(string(body) + "\n\n") + } else { + sepIndex += len(sepStr) + payload, _ := printJSON(body[sepIndex:]) + b.WriteString(string(body[:sepIndex]) + string(payload) + "\n\n") + } + + return b.String() +} + +// LogHTTPResponse ... +func (l *Logger) LogHTTPResponse(data []byte, status int, startTime time.Time) string { + duration := time.Now().Sub(startTime) + jsonData, _ := printJSON(data) + return fmt.Sprintf("Response:\n%d %v %dB\n%s\n%s\n\n", status, duration, len(data), jsonData, splitLine) +} + +// CombineHTTPLogs ... +func (l *Logger) CombineHTTPLogs(in string, out string) { + if l.outputFile == nil { + return + } + + l.mu.Lock() + defer l.mu.Unlock() + + msg := in + out + if l.shouldSplit(len(msg)) { + l.split() + } + l.outputFile.WriteString(msg) +} diff --git a/logger/main.go b/logger/main.go new file mode 100644 index 0000000..d85b871 --- /dev/null +++ b/logger/main.go @@ -0,0 +1,162 @@ +package logger + +import ( + "bytes" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + "sync" + "time" +) + +const dateTimeFormat = "2006-01-02 15:04:05" + +// Block ... +const ( + MaxLogSize5MB int64 = 5 * 1024 * 1024 + MaxLogSize1MB int64 = 1 * 1024 * 1024 + MaxLogSize500KB int64 = 500 * 1024 + MaxLogSize100KB int64 = 100 * 1024 + MaxLogSize512B int64 = 512 +) + +// Logger ... +type Logger struct { + mu *sync.Mutex + outputFile *os.File + + outputFileName string + fullName string + maxFileSize int64 + + splitCount int + + directory string +} + +// New ... +func New(name, dir string, maxFileSize int64) (logger *Logger, err error) { + logger = &Logger{} + + logger.outputFileName = name + logger.mu = &sync.Mutex{} + logger.maxFileSize = maxFileSize + logger.directory = dir + + err = os.Mkdir(dir, os.ModePerm) + if err != nil { + if !os.IsExist(err) { + return nil, err + } + } + + date := strings.Replace(time.Now().Format(dateTimeFormat), ":", ".", -1) + logger.outputFileName += " " + date + logger.fullName = logger.outputFileName + ".txt" + path := filepath.Join(dir, logger.fullName) + if logger.outputFile, err = os.Create(path); err != nil { + return nil, err + } + + return logger, nil +} + +// Log ... +func (l *Logger) Log(format string, v ...interface{}) { + if l.outputFile == nil { + return + } + + l.mu.Lock() + defer l.mu.Unlock() + + msg := fmt.Sprintf(format, v...) + s := time.Now().Format(dateTimeFormat) + ": " + msg + "\n" + if l.shouldSplit(len(s)) { + l.split() + } + l.outputFile.WriteString(s) +} + +// Print ... +func (l *Logger) Print(format string, v ...interface{}) { + msg := fmt.Sprintf(format, v...) + fmt.Printf("%s: %s\n", time.Now().Format(dateTimeFormat), msg) +} + +// Trace ... +func (l *Logger) Trace(format string, v ...interface{}) string { + if l.outputFile == nil { + return "" + } + + l.mu.Lock() + defer l.mu.Unlock() + + s := getTrace(format, v...) + "\n" + + if l.shouldSplit(len(s)) { + l.split() + } + l.outputFile.WriteString(s) + + return s +} + +// PrintTrace ... +func (l *Logger) PrintTrace(format string, v ...interface{}) { + s := getTrace(format, v...) + fmt.Printf("%s\n", s) +} + +// PrintAndTrace ... +func (l *Logger) PrintAndTrace(format string, v ...interface{}) { + t := l.Trace(format, v...) + fmt.Println(t) +} + +// Close ... +func (l *Logger) Close() error { + if l.outputFile == nil { + return nil + } + + return l.outputFile.Close() +} + +// GetOutDir ... +func (l *Logger) GetOutDir() string { + return l.directory +} + +func (l *Logger) split() error { + if l.outputFile == nil { + return nil + } + + // close old file + err := l.outputFile.Close() + if err != nil { + return err + } + + // open new file + l.splitCount++ + path := filepath.Join(l.directory, l.outputFileName+fmt.Sprintf("(%d)", l.splitCount)+".txt") + l.outputFile, err = os.Create(path) + + return err +} + +func (l *Logger) shouldSplit(nextEntrySize int) bool { + stats, _ := l.outputFile.Stat() + return int64(nextEntrySize) >= (l.maxFileSize - stats.Size()) +} + +func printJSON(in []byte) (out []byte, err error) { + var buf bytes.Buffer + err = json.Indent(&buf, in, "", " ") + return buf.Bytes(), err +} diff --git a/logger/tracing.go b/logger/tracing.go new file mode 100644 index 0000000..a138e5c --- /dev/null +++ b/logger/tracing.go @@ -0,0 +1,65 @@ +package logger + +import ( + "fmt" + "math" + "runtime" + "strings" + "time" +) + +// getCallStack +func getCallStack() (stack []string) { + const ( + maxStackDepth = 10000 + skipRuntime = 2 // skip runtime and startup + skipCallers = 2 + thisPackage = "logger" + ) + + callers := make([]uintptr, maxStackDepth) // min 1 + + stackDepth := runtime.Callers(skipCallers, callers) + frames := runtime.CallersFrames(callers) + + for i := 0; i < skipRuntime; i++ { + frames.Next() + } + + for i := 0; i < stackDepth-skipRuntime-skipCallers; i++ { + frame, next := frames.Next() + if !strings.Contains(frame.File, thisPackage) { + stack = append(stack, fmt.Sprintf("[%s %d]", frame.File, frame.Line)) + } + if !next { + break + } + } + + reverseStack(stack) + + return stack +} + +// in place +func reverseStack(stack []string) { + middle := int(math.Floor(float64(len(stack)) / 2.0)) + + lastIndex := len(stack) - 1 + for i := 0; i < middle; i++ { + stack[i], stack[lastIndex] = stack[lastIndex], stack[i] + lastIndex-- + } +} + +func getTrace(format string, v ...interface{}) (t string) { + stack := getCallStack() + + t = time.Now().Format(dateTimeFormat) + ":\n" + for _, s := range stack { + t += s + "\n" + } + t += fmt.Sprintf(format, v...) + "\n" + + return t +} diff --git a/quicksort.go b/quicksort.go index 70fade7..ec8ec74 100644 --- a/quicksort.go +++ b/quicksort.go @@ -1,51 +1,32 @@ package webutility -type QSortDirection int +import "sort" -const ( - QSortAscending QSortDirection = iota - QSortDescending -) - -// QuickSortable is an interface for quicksorting slices. -type QuickSortable interface { - Swap(i, j int) - Compare(i, j int) int - Len() int -} - -// Quicksort quicksorts que. -func Quicksort(que QuickSortable, low, high int, dir QSortDirection) { +// QuickSort quicksorts que. +func QuickSort(que sort.Interface, low, high int, reverse bool) { if low >= high { return } - if dir != QSortAscending && dir != QSortDescending { - return - } - - index := partition(que, low, high, dir) - Quicksort(que, low, index-1, dir) - Quicksort(que, index+1, high, dir) + index := quickSortPartition(que, low, high, reverse) + QuickSort(que, low, index-1, reverse) + QuickSort(que, index+1, high, reverse) } -func partition(que QuickSortable, low, high int, dir QSortDirection) int { - swap := 0 - // -1 -> i > j - // 1 -> i < j - if dir == QSortDescending { - swap = -1 - } else { - swap = 1 - } - +func quickSortPartition(que sort.Interface, low, high int, reverse bool) int { i := low - 1 for j := low; j <= high-1; j++ { - if que.Compare(j, high) == swap { - i++ - que.Swap(i, j) + if !reverse { + if que.Less(j, high) { + i++ + que.Swap(i, j) + } + } else { + if !que.Less(j, high) { + i++ + que.Swap(i, j) + } } - continue } que.Swap(i+1, high) return i + 1 diff --git a/server.go b/server.go index 1531a6a..2a55bc2 100644 --- a/server.go +++ b/server.go @@ -5,14 +5,14 @@ import ( "fmt" "net/http" - "git.to-net.rs/marko.tikvic/gologger" + "git.to-net.rs/marko.tikvic/webutility/logger" "github.com/gorilla/mux" ) type Server struct { DB *sql.DB Router *mux.Router - Logger *gologger.Logger + Logger *logger.Logger Port string DBs map[string]*sql.DB dsn map[string]string @@ -29,7 +29,7 @@ func NewODBCServer(dsn, port, logDir string) (s *Server, err error) { s.Router = mux.NewRouter() - if s.Logger, err = gologger.New("err", logDir, gologger.MaxLogSize1MB); err != nil { + if s.Logger, err = logger.New("err", logDir, logger.MaxLogSize1MB); err != nil { return nil, fmt.Errorf("can't create logger: %s", err.Error()) }