feat: complete contract-driven business development and MySQL integration
This commit is contained in:
67
logx/adapters.go
Normal file
67
logx/adapters.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package logx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"log"
|
||||
"log/slog"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Validate checks configuration without opening files or creating resources.
|
||||
func (c Config) Validate() error {
|
||||
c = normalizeConfig(c)
|
||||
if _, err := parseLevel(c.Level); err != nil {
|
||||
return errors.New("logx: invalid level")
|
||||
}
|
||||
if c.Format != "json" && c.Format != "text" {
|
||||
return errors.New("logx: format must be json or text")
|
||||
}
|
||||
switch c.Output {
|
||||
case "stdout", "stderr", "discard", "none":
|
||||
default:
|
||||
return errors.New("logx: invalid output")
|
||||
}
|
||||
return c.Rotation.validate(c)
|
||||
}
|
||||
|
||||
type loggerContextKey struct{}
|
||||
|
||||
// WithLogger borrows a logger for a call tree; it does not alter the global
|
||||
// default and does not transfer ownership. nil preserves the existing context.
|
||||
func WithLogger(ctx context.Context, logger *Logger) context.Context {
|
||||
ctx = normalizeContext(ctx)
|
||||
if logger == nil {
|
||||
return ctx
|
||||
}
|
||||
return context.WithValue(ctx, loggerContextKey{}, logger)
|
||||
}
|
||||
|
||||
// FromContext returns a call-scoped logger, falling back to package logging.
|
||||
func FromContext(ctx context.Context) *Logger {
|
||||
if ctx != nil {
|
||||
if l, ok := ctx.Value(loggerContextKey{}).(*Logger); ok && l != nil {
|
||||
return l
|
||||
}
|
||||
}
|
||||
return defaultLogger.Load()
|
||||
}
|
||||
|
||||
// Standard adapts this instance to the standard logger (for http.Server etc).
|
||||
// It borrows the writer and never closes it. Each Print call becomes one event.
|
||||
func (l *Logger) Standard(level slog.Level) *log.Logger {
|
||||
if l == nil {
|
||||
l = defaultLogger.Load()
|
||||
}
|
||||
return log.New(standardWriter{logger: l, level: level}, "", 0)
|
||||
}
|
||||
|
||||
type standardWriter struct {
|
||||
logger *Logger
|
||||
level slog.Level
|
||||
}
|
||||
|
||||
func (w standardWriter) Write(p []byte) (int, error) {
|
||||
w.logger.logger.Log(context.Background(), w.level, strings.TrimRight(string(p), "\r\n"))
|
||||
return len(p), nil
|
||||
}
|
||||
33
logx/adapters_test.go
Normal file
33
logx/adapters_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package logx
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidateBeforeOpeningWriter(t *testing.T) {
|
||||
p := filepath.Join(t.TempDir(), "must-not-exist.log")
|
||||
for _, cfg := range []Config{{File: p, Format: "typo"}, {File: p, Level: "typo"}, {File: p, Output: "typo"}} {
|
||||
if cfg.Validate() == nil {
|
||||
t.Fatal("invalid configuration accepted")
|
||||
}
|
||||
if _, err := New(cfg); err == nil {
|
||||
t.Fatal("invalid logger created")
|
||||
}
|
||||
if _, err := os.Stat(p); !os.IsNotExist(err) {
|
||||
t.Fatal("validation touched filesystem", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
func TestStandardLoggerUsesBorrowedInstance(t *testing.T) {
|
||||
var out bytes.Buffer
|
||||
l, _ := New(Config{Writer: &out})
|
||||
l.Standard(slog.LevelWarn).Print("driver diagnostic")
|
||||
if !strings.Contains(out.String(), `"level":"WARN"`) || !strings.Contains(out.String(), "driver diagnostic") {
|
||||
t.Fatal(out.String())
|
||||
}
|
||||
}
|
||||
12
logx/logx.go
12
logx/logx.go
@@ -73,7 +73,7 @@ func init() {
|
||||
// call Close when the process is shutting down.
|
||||
func New(cfg Config) (*Logger, error) {
|
||||
cfg = normalizeConfig(cfg)
|
||||
if err := cfg.Rotation.validate(cfg); err != nil {
|
||||
if err := cfg.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
level, err := parseLevel(cfg.Level)
|
||||
@@ -225,7 +225,7 @@ func (l *Logger) ErrorStackContext(ctx context.Context, msg string, args ...any)
|
||||
}
|
||||
|
||||
func ErrorStackContext(ctx context.Context, msg string, args ...any) {
|
||||
defaultLogger.Load().ErrorStackContext(ctx, msg, args...)
|
||||
FromContext(ctx).ErrorStackContext(ctx, msg, args...)
|
||||
}
|
||||
|
||||
func (l *Logger) Debug(msg string, args ...any) { l.DebugContext(context.Background(), msg, args...) }
|
||||
@@ -234,19 +234,19 @@ func (l *Logger) Warn(msg string, args ...any) { l.WarnContext(context.Backgrou
|
||||
func (l *Logger) Error(msg string, args ...any) { l.ErrorContext(context.Background(), msg, args...) }
|
||||
|
||||
func DebugContext(ctx context.Context, msg string, args ...any) {
|
||||
defaultLogger.Load().DebugContext(ctx, msg, args...)
|
||||
FromContext(ctx).DebugContext(ctx, msg, args...)
|
||||
}
|
||||
|
||||
func InfoContext(ctx context.Context, msg string, args ...any) {
|
||||
defaultLogger.Load().InfoContext(ctx, msg, args...)
|
||||
FromContext(ctx).InfoContext(ctx, msg, args...)
|
||||
}
|
||||
|
||||
func WarnContext(ctx context.Context, msg string, args ...any) {
|
||||
defaultLogger.Load().WarnContext(ctx, msg, args...)
|
||||
FromContext(ctx).WarnContext(ctx, msg, args...)
|
||||
}
|
||||
|
||||
func ErrorContext(ctx context.Context, msg string, args ...any) {
|
||||
defaultLogger.Load().ErrorContext(ctx, msg, args...)
|
||||
FromContext(ctx).ErrorContext(ctx, msg, args...)
|
||||
}
|
||||
|
||||
func Debug(msg string, args ...any) { DebugContext(context.Background(), msg, args...) }
|
||||
|
||||
Reference in New Issue
Block a user