This commit is contained in:
Suyono 2023-09-09 14:07:49 +10:00
parent 8a480acde7
commit 5f7befe02c
6 changed files with 173 additions and 53 deletions

View File

@ -7,7 +7,11 @@ type Trace struct {
} }
func (t *Trace) Error() string { func (t *Trace) Error() string {
return "[debug trace available]" return ""
}
func (t *Trace) Trace() []string {
return nil
} }
func GetTraces() error { func GetTraces() error {

View File

@ -3,5 +3,5 @@ package debugframes
type PanicTrace []byte type PanicTrace []byte
func (p PanicTrace) Error() string { func (p PanicTrace) Error() string {
return "[panic trace available]" return ""
} }

27
log/errlog_test.go Normal file
View File

@ -0,0 +1,27 @@
package log
import (
"errors"
"github.com/rs/zerolog"
"testing"
)
func TestPrint(t *testing.T) {
Print("key", errors.New("hello world"))
}
type testWriter struct {
}
func (t testWriter) Write(b []byte) (int, error) {
return 0, errors.New("write error")
}
func TestErrWrite(t *testing.T) {
var (
tw testWriter
logger zerolog.Logger
)
logger = zerolog.New(tw)
logger.Error().Str("test", "one").Msg("hello")
}

View File

@ -7,17 +7,18 @@ import (
"github.com/spf13/viper" "github.com/spf13/viper"
) )
type File struct { type File os.File
path string
file *os.File
}
const ( const (
filenameKey = "file" filenameKey = "file"
) )
func NewLogFile(configKey string) (*File, error) { func NewLogFile(configKey string) (*File, error) {
var err error var (
err error
path string
file *os.File
)
if viper.IsSet(configKey) { if viper.IsSet(configKey) {
return nil, nil return nil, nil
} }
@ -27,22 +28,23 @@ func NewLogFile(configKey string) (*File, error) {
return nil, fmt.Errorf("missing file key config %s", fileKey) return nil, fmt.Errorf("missing file key config %s", fileKey)
} }
file := &File{ path = viper.GetString(fileKey)
path: viper.GetString(fileKey), if file, err = os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err != nil {
}
if file.file, err = os.OpenFile(file.path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err != nil {
return nil, err return nil, err
} }
return file, nil return (*File)(file), nil
} }
func (f *File) Write(b []byte) (int, error) { func (f *File) Write(b []byte) (int, error) {
return 0, nil var file *os.File
file = (*os.File)(f)
return file.Write(b)
} }
func (f *File) Close() error { func (f *File) Close() error {
return f.file.Close() of := (*os.File)(f)
return of.Close()
} }
func (f *File) Rotate() error { func (f *File) Rotate() error {

View File

@ -1,9 +1,10 @@
package log package log
import ( import (
"os" "fmt"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"io"
"os"
) )
type Level zerolog.Level type Level zerolog.Level
@ -15,6 +16,11 @@ type ProcessLogConfig interface {
FileName() string FileName() string
} }
type Traceable interface {
error
Trace() []string
}
const ( const (
Trace Level = Level(zerolog.TraceLevel) Trace Level = Level(zerolog.TraceLevel)
Debug Level = Level(zerolog.DebugLevel) Debug Level = Level(zerolog.DebugLevel)
@ -28,42 +34,41 @@ const (
) )
var ( var (
globalLevel Level = Error globalLevel Level = Error
logger zerolog.Logger logger zerolog.Logger
onLogWriterError zerolog.Logger
writer *Writer
DefaultOutlet io.Writer
) )
func init() { func init() {
DefaultOutlet = os.Stderr
writer = NewWriter()
logger = zerolog.New(writer)
onLogWriterError = logger.Output(DefaultOutlet)
SetGlobalLevel(globalLevel) SetGlobalLevel(globalLevel)
logger = zerolog.New(os.Stderr)
} }
func (l Level) Print(a ...any) { func (l Level) Print(a ...any) {
// var event *zerolog.Event l.Fields(a...).Send()
// for _, i := range a {
// if event == nil {
// event = logger.WithLevel(zerolog.Level(l))
// }
// switch v := i.(type) {
// case daemon.ProcessLogEntry:
// event = event.Str("type", v.Descriptor.InstanceType().String()).Str("origin", "child process").
// Str("name", v.Descriptor.Name())
// if v.Descriptor.InstanceType() == daemon.Cron {
// event = event.Str("instance_name", v.Descriptor.InstanceName())
// }
// event.Str("entry", v.LogEntry).Send()
// event = nil
// //TODO: add logic to process cron or service specific log config
// }
// }
} }
func (l Level) Fields(a ...any) *Payload { func (l Level) PrintTo(outlets []io.Writer, a ...any) {
l.Fields(a...).Send(outlets...)
}
func (l Level) Fields(a ...any) (p *Payload) {
p = (*Payload)(logger.WithLevel(zerolog.Level(l)).Timestamp())
return p.Fields(a...)
}
func (p *Payload) Fields(a ...any) *Payload {
var ( var (
event *zerolog.Event event *zerolog.Event
key string key string
) )
event = logger.WithLevel(zerolog.Level(l)) event = (*zerolog.Event)(p)
for i, part := range a { for i, part := range a {
if i%2 == 0 { if i%2 == 0 {
key = part.(string) key = part.(string)
@ -71,16 +76,39 @@ func (l Level) Fields(a ...any) *Payload {
switch v := part.(type) { switch v := part.(type) {
case string: case string:
event = event.Str(key, v) event = event.Str(key, v)
case error:
event = event.Err(v)
default:
event = event.Str(key, fmt.Sprintf("[no data type handle] %v", v))
} }
} }
} }
return nil return (*Payload)(event)
}
func (p *Payload) Send(ws ...io.Writer) {
event := (*zerolog.Event)(p)
writer.Lock()
defer writer.Unlock()
if len(ws) == 0 {
writer.Writers(DefaultOutlet)
} else {
writer.Writers(ws...)
}
event.Send()
} }
func Print(a ...any) { func Print(a ...any) {
globalLevel.Print(a...) globalLevel.Print(a...)
} }
func PrintTo(outlets []io.Writer, a ...any) {
globalLevel.PrintTo(outlets, a...)
}
func SetGlobalLevel(l Level) { func SetGlobalLevel(l Level) {
globalLevel = l globalLevel = l
zerolog.SetGlobalLevel(zerolog.Level(globalLevel)) zerolog.SetGlobalLevel(zerolog.Level(globalLevel))

View File

@ -1,31 +1,90 @@
package log package log
import ( import (
"errors"
"fmt"
"io" "io"
"sync" "sync"
) )
type Writer struct { var (
writer io.Writer noError = errors.New("no error")
mtx *sync.Mutex ec = make(chan error)
} //TODO: create a writer implementation using this struct, ensure sync and prevent abrupt truncation when stopping )
func NewWriter(w io.Writer) *Writer { type Writer struct {
writers []io.Writer
mtx *sync.Mutex
}
func NewWriter() *Writer {
return &Writer{ return &Writer{
writer: w, writers: make([]io.Writer, 0),
mtx: &sync.Mutex{}, mtx: &sync.Mutex{},
} }
} }
func (w *Writer) Write(b []byte) (int, error) { func (w *Writer) Write(b []byte) (int, error) {
w.mtx.Lock() var (
defer w.mtx.Unlock() ctr int
return w.writer.Write(b) sw io.Writer
} err error
)
func (w *Writer) Close() { for _, ww := range w.writers {
if wc, ok := w.writer.(io.WriteCloser); ok { if ww == DefaultOutlet {
_ = wc.Close() sw = ww
} else {
ctr++
go subWriter(ww, b, ec)
}
} }
if sw != nil {
_, _ = sw.Write(b)
}
for i := 0; i < ctr; i++ {
if err = <-ec; err != noError {
onLogWriterError.Error().Err(err).Msg("subWriter error")
}
}
return len(b), nil
} }
func (w *Writer) Lock() {
w.mtx.Lock()
}
func (w *Writer) Unlock() {
w.writers[0] = DefaultOutlet
w.writers = w.writers[:1]
w.mtx.Unlock()
}
func (w *Writer) Writers(ws ...io.Writer) {
if len(ws) == 0 {
w.writers[0] = DefaultOutlet
w.writers = w.writers[:1]
} else {
w.writers = append(w.writers, ws...)
}
}
func subWriter(w io.Writer, b []byte, errchan chan<- error) {
defer func() {
if o := recover(); o != nil {
errchan <- fmt.Errorf("subWriter panic: %v", o)
}
}()
if _, err := w.Write(b); err != nil {
errchan <- err
} else {
errchan <- noError
}
}
//func (w *Writer) Close() {
//}