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 {
return "[debug trace available]"
return ""
}
func (t *Trace) Trace() []string {
return nil
}
func GetTraces() error {

View File

@ -3,5 +3,5 @@ package debugframes
type PanicTrace []byte
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"
)
type File struct {
path string
file *os.File
}
type File os.File
const (
filenameKey = "file"
)
func NewLogFile(configKey string) (*File, error) {
var err error
var (
err error
path string
file *os.File
)
if viper.IsSet(configKey) {
return nil, nil
}
@ -27,22 +28,23 @@ func NewLogFile(configKey string) (*File, error) {
return nil, fmt.Errorf("missing file key config %s", fileKey)
}
file := &File{
path: viper.GetString(fileKey),
}
if file.file, err = os.OpenFile(file.path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err != nil {
path = viper.GetString(fileKey)
if file, err = os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err != nil {
return nil, err
}
return file, nil
return (*File)(file), nil
}
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 {
return f.file.Close()
of := (*os.File)(f)
return of.Close()
}
func (f *File) Rotate() error {

View File

@ -1,9 +1,10 @@
package log
import (
"os"
"fmt"
"github.com/rs/zerolog"
"io"
"os"
)
type Level zerolog.Level
@ -15,6 +16,11 @@ type ProcessLogConfig interface {
FileName() string
}
type Traceable interface {
error
Trace() []string
}
const (
Trace Level = Level(zerolog.TraceLevel)
Debug Level = Level(zerolog.DebugLevel)
@ -28,42 +34,41 @@ const (
)
var (
globalLevel Level = Error
logger zerolog.Logger
globalLevel Level = Error
logger zerolog.Logger
onLogWriterError zerolog.Logger
writer *Writer
DefaultOutlet io.Writer
)
func init() {
DefaultOutlet = os.Stderr
writer = NewWriter()
logger = zerolog.New(writer)
onLogWriterError = logger.Output(DefaultOutlet)
SetGlobalLevel(globalLevel)
logger = zerolog.New(os.Stderr)
}
func (l Level) Print(a ...any) {
// var event *zerolog.Event
// 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
// }
// }
l.Fields(a...).Send()
}
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 (
event *zerolog.Event
key string
)
event = logger.WithLevel(zerolog.Level(l))
event = (*zerolog.Event)(p)
for i, part := range a {
if i%2 == 0 {
key = part.(string)
@ -71,16 +76,39 @@ func (l Level) Fields(a ...any) *Payload {
switch v := part.(type) {
case string:
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) {
globalLevel.Print(a...)
}
func PrintTo(outlets []io.Writer, a ...any) {
globalLevel.PrintTo(outlets, a...)
}
func SetGlobalLevel(l Level) {
globalLevel = l
zerolog.SetGlobalLevel(zerolog.Level(globalLevel))

View File

@ -1,31 +1,90 @@
package log
import (
"errors"
"fmt"
"io"
"sync"
)
type Writer struct {
writer io.Writer
mtx *sync.Mutex
} //TODO: create a writer implementation using this struct, ensure sync and prevent abrupt truncation when stopping
var (
noError = errors.New("no error")
ec = make(chan error)
)
func NewWriter(w io.Writer) *Writer {
type Writer struct {
writers []io.Writer
mtx *sync.Mutex
}
func NewWriter() *Writer {
return &Writer{
writer: w,
mtx: &sync.Mutex{},
writers: make([]io.Writer, 0),
mtx: &sync.Mutex{},
}
}
func (w *Writer) Write(b []byte) (int, error) {
w.mtx.Lock()
defer w.mtx.Unlock()
return w.writer.Write(b)
}
var (
ctr int
sw io.Writer
err error
)
func (w *Writer) Close() {
if wc, ok := w.writer.(io.WriteCloser); ok {
_ = wc.Close()
for _, ww := range w.writers {
if ww == DefaultOutlet {
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() {
//}