update field (#8)
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/tag Build is failing

Reviewed-on: #8
Co-authored-by: andrey <andrey@4devs.io>
Co-committed-by: andrey <andrey@4devs.io>
This commit was merged in pull request #8.
This commit is contained in:
2024-01-02 15:45:34 +03:00
parent a3091c4eb6
commit abbcf0b1a0
30 changed files with 1893 additions and 1825 deletions

View File

@@ -1,119 +1,129 @@
package log
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"os"
"strings"
"sync"
"gitoa.ru/go-4devs/log/entry"
"gitoa.ru/go-4devs/log/field"
"gitoa.ru/go-4devs/log/internal/buffer"
)
// Keys for "built-in" attributes.
const (
// TimeKey is the key used by the built-in handlers for the time
// when the log method is called. The associated Value is a [time.Time].
KeyTime = "time"
// LevelKey is the key used by the built-in handlers for the level
// of the log call. The associated value is a [Level].
KeyLevel = "level"
// MessageKey is the key used by the built-in handlers for the
// message of the log call. The associated value is a string.
KeyMessage = "msg"
// SourceKey is the key used by the built-in handlers for the source file
// and line of the log call. The associated value is a string.
KeySource = "source"
)
func WithWriter(w io.Writer) func(*option) {
return func(o *option) {
o.out = w
}
}
func WithStdout() func(*option) {
return func(o *option) {
o.out = os.Stdout
}
}
// WithStringFormat sets format as simple string.
func WithStringFormat() func(*option) {
return func(o *option) {
o.format = formatText()
}
}
// WithJSONFormat sets json output format.
func WithJSONFormat() func(*option) {
return func(o *option) {
o.format = formatJSON()
}
}
type option struct {
format func(io.Writer, *entry.Entry) (int, error)
out io.Writer
}
// New creates standart logger.
func New(opts ...Option) Logger {
logger := log{e: stringFormat(), w: os.Stderr}
func New(opts ...func(*option)) Logger {
log := option{
format: formatText(),
out: os.Stderr,
}
for _, opt := range opts {
opt(&logger)
opt(&log)
}
return func(_ context.Context, entry *entry.Entry) (int, error) {
b, err := logger.e(entry)
if err != nil {
return 0, fmt.Errorf("enode err: %w", err)
return log.format(log.out, entry)
}
}
func formatText() func(io.Writer, *entry.Entry) (int, error) {
enc := field.NewEncoderText()
return func(w io.Writer, entry *entry.Entry) (int, error) {
buf := buffer.New()
defer func() {
buf.Free()
}()
*buf = enc.AppendField(*buf, field.String(KeyMessage, entry.Message()))
for _, field := range entry.Fields() {
*buf = enc.AppendField(*buf, field)
}
n, err := logger.w.Write(b)
_, _ = buf.WriteString("\n")
n, err := w.Write(*buf)
if err != nil {
return 0, fmt.Errorf("failed write: %w", err)
return 0, fmt.Errorf("format text:%w", err)
}
return n, nil
}
}
// 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)
}
// 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())
}
// WithJSONFormat sets json output format.
func WithJSONFormat() Option {
return WithEncode(jsonFormat)
}
//nolint:forcetypeassert
func stringFormat() func(entry *entry.Entry) ([]byte, error) {
pool := sync.Pool{
New: func() interface{} {
return &bytes.Buffer{}
},
}
return func(entry *entry.Entry) ([]byte, error) {
buf := pool.Get().(*bytes.Buffer)
buf.Reset()
func formatJSON() func(w io.Writer, entry *entry.Entry) (int, error) {
enc := field.NewEncoderJSON()
return func(w io.Writer, entry *entry.Entry) (int, error) {
buf := buffer.New()
defer func() {
pool.Put(buf)
buf.Free()
}()
buf.WriteString("msg=\"")
buf.WriteString(strings.TrimSpace(entry.Message()))
buf.WriteString("\"")
_, _ = buf.WriteString("{")
*buf = enc.AppendField(*buf, field.String(KeyMessage, entry.Message()))
for _, field := range entry.Fields() {
buf.WriteString(" ")
buf.WriteString(string(field.Key()))
buf.WriteString("=")
buf.WriteString(field.Value().String())
*buf = enc.AppendField(*buf, field)
}
buf.WriteString("\n")
_, _ = buf.WriteString("}")
_, _ = buf.WriteString("\n")
return buf.Bytes(), nil
n, err := w.Write(*buf)
if err != nil {
return 0, fmt.Errorf("format json:%w", err)
}
return n, nil
}
}
func jsonFormat(entry *entry.Entry) ([]byte, error) {
res, err := json.Marshal(entry.AddString("msg", entry.Message()).Fields().AsMap())
if err != nil {
return nil, fmt.Errorf("marshal err: %w", err)
}
return append(res, []byte("\n")...), nil
}