You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

120 lines
2.1 KiB

3 years ago
package log
import (
"bytes"
"context"
"encoding/json"
3 years ago
"fmt"
3 years ago
"io"
"os"
"strings"
"sync"
"gitoa.ru/go-4devs/log/entry"
)
// New creates standart logger.
func New(opts ...Option) Logger {
l := log{e: stringFormat(), w: os.Stderr}
for _, opt := range opts {
opt(&l)
}
return func(_ context.Context, entry *entry.Entry) (int, error) {
b, err := l.e(entry)
if err != nil {
3 years ago
return 0, fmt.Errorf("enode err: %w", err)
3 years ago
}
3 years ago
n, err := l.w.Write(b)
if err != nil {
return 0, fmt.Errorf("failed write: %w", err)
}
return n, nil
3 years ago
}
}
// Option configure log.
type Option func(*log)
// Encode sets formats and encode output message.
type Encode func(*entry.Entry) ([]byte, error)
type log struct {
w io.Writer
e Encode
}
// WithWriter sets writer logger.
func WithWriter(writer io.Writer) Option {
return func(l *log) {
l.w = writer
}
}
// WithStdout sets logged to os.Stdout.
func WithStdout() Option {
return WithWriter(os.Stdout)
3 years ago
}
// WithEncode sets format log.
func WithEncode(e Encode) Option {
return func(l *log) {
l.e = e
}
}
// WithStringFormat sets format as simple string.
func WithStringFormat() Option {
return WithEncode(stringFormat())
3 years ago
}
// WithJSONFormat sets json output format.
func WithJSONFormat() Option {
return WithEncode(jsonFormat)
3 years ago
}
3 years ago
//nolint: forcetypeassert
3 years ago
func stringFormat() func(entry *entry.Entry) ([]byte, error) {
pool := sync.Pool{
New: func() interface{} {
return &bytes.Buffer{}
},
}
return func(entry *entry.Entry) ([]byte, error) {
b := pool.Get().(*bytes.Buffer)
b.Reset()
defer func() {
pool.Put(b)
}()
b.WriteString("msg=\"")
b.WriteString(strings.TrimSpace(entry.Message()))
b.WriteString("\"")
for _, field := range entry.Fields() {
b.WriteString(" ")
b.WriteString(string(field.Key()))
b.WriteString("=")
b.WriteString(field.Value().String())
}
b.WriteString("\n")
return b.Bytes(), nil
}
}
func jsonFormat(entry *entry.Entry) ([]byte, error) {
res, err := json.Marshal(entry.AddString("msg", entry.Message()).Fields().AsMap())
if err != nil {
3 years ago
return nil, fmt.Errorf("marshal err: %w", err)
3 years ago
}
return append(res, []byte("\n")...), nil
}