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.

188 lines
4.3 KiB

3 years ago
package log
import (
"context"
"fmt"
3 years ago
"io"
"os"
"gitoa.ru/go-4devs/log/entry"
"gitoa.ru/go-4devs/log/field"
"gitoa.ru/go-4devs/log/internal/buffer"
3 years ago
)
// 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"
// KeyName logger name.
KeyName = "name"
)
3 years ago
func WithWriter(w io.Writer) func(*option) {
return func(o *option) {
o.out = w
3 years ago
}
}
3 years ago
func WithStdout() func(*option) {
return func(o *option) {
o.out = os.Stdout
3 years ago
}
}
// WithStringFormat sets format as simple string.
func WithStringFormat() func(*option) {
return WithFormat(FormatString(field.NewEncoderText()))
3 years ago
}
// WithJSONFormat sets json output format.
func WithJSONFormat() func(*option) {
return WithFormat(FormatJSON(field.NewEncoderJSON()))
}
// WithFormat sets custom output format.
func WithFormat(format func(io.Writer, *entry.Entry) (int, error)) func(*option) {
return func(o *option) {
o.format = format
3 years ago
}
}
type option struct {
format func(io.Writer, *entry.Entry) (int, error)
out io.Writer
3 years ago
}
// New creates standart logger.
func New(opts ...func(*option)) Logger {
log := option{
format: FormatString(field.NewEncoderText()),
out: os.Stderr,
3 years ago
}
for _, opt := range opts {
opt(&log)
}
3 years ago
return func(_ context.Context, entry *entry.Entry) (int, error) {
return log.format(log.out, entry)
3 years ago
}
}
3 years ago
type Encoder interface {
AppendValue(dst []byte, val field.Value) []byte
AppendField(dst []byte, val field.Field) []byte
}
func FormatWithBracket(enc Encoder) func(io.Writer, *entry.Entry) (int, error) {
appendValue := func(buf *buffer.Buffer, data field.Fields, key, prefix, suffix string) *buffer.Buffer {
data.Fields(
func(f field.Field) bool {
if f.IsKey(key) {
_, _ = buf.WriteString(prefix)
*buf = enc.AppendValue(*buf, f.Value)
_, _ = buf.WriteString(suffix)
return false
}
return true
})
return buf
}
return func(w io.Writer, data *entry.Entry) (int, error) {
buf := buffer.New()
defer func() {
buf.Free()
}()
fields := data.Fields()
buf = appendValue(buf, fields, KeyTime, "", " ")
_, _ = buf.WriteString("[")
*buf = enc.AppendValue(*buf, field.StringValue(data.Level().String()))
_, _ = buf.WriteString("]")
buf = appendValue(buf, fields, KeyName, "[", "]")
buf = appendValue(buf, fields, KeySource, " ", " ")
*buf = enc.AppendValue(*buf, field.StringValue(data.Message()))
fields.Fields(func(f field.Field) bool {
if !f.IsKey(KeyTime, KeySource, KeyName, KeyLevel) {
*buf = enc.AppendField(*buf, f)
}
return true
})
_, _ = buf.WriteString("\n")
n, err := w.Write(*buf)
if err != nil {
return 0, fmt.Errorf("format text:%w", err)
}
return n, nil
}
}
func FormatString(enc Encoder) func(io.Writer, *entry.Entry) (int, error) {
return func(w io.Writer, entry *entry.Entry) (int, error) {
buf := buffer.New()
3 years ago
defer func() {
buf.Free()
3 years ago
}()
*buf = enc.AppendField(*buf, field.String(KeyMessage, entry.Message()))
3 years ago
for _, field := range entry.Fields() {
*buf = enc.AppendField(*buf, field)
3 years ago
}
_, _ = buf.WriteString("\n")
n, err := w.Write(*buf)
if err != nil {
return 0, fmt.Errorf("format text:%w", err)
}
3 years ago
return n, nil
3 years ago
}
}
func FormatJSON(enc Encoder) func(w io.Writer, entry *entry.Entry) (int, error) {
return func(w io.Writer, entry *entry.Entry) (int, error) {
buf := buffer.New()
defer func() {
buf.Free()
}()
_, _ = buf.WriteString("{")
*buf = enc.AppendField(*buf, field.String(KeyMessage, entry.Message()))
for _, field := range entry.Fields() {
*buf = enc.AppendField(*buf, field)
}
_, _ = buf.WriteString("}")
_, _ = buf.WriteString("\n")
n, err := w.Write(*buf)
if err != nil {
return 0, fmt.Errorf("format json:%w", err)
}
return n, nil
}
3 years ago
}