...

Source file src/oss.terrastruct.com/d2/lib/log/log.go

Documentation: oss.terrastruct.com/d2/lib/log

     1  // Package log is a context wrapper around slog.Logger
     2  package log
     3  
     4  import (
     5  	"context"
     6  	"log"
     7  	stdlog "log"
     8  	"os"
     9  	"runtime/debug"
    10  	"testing"
    11  
    12  	"cdr.dev/slog"
    13  	"cdr.dev/slog/sloggers/sloghuman"
    14  	"cdr.dev/slog/sloggers/slogtest"
    15  
    16  	"oss.terrastruct.com/d2/lib/env"
    17  )
    18  
    19  var _default = slog.Make(sloghuman.Sink(os.Stderr)).Named("default")
    20  
    21  func Init() {
    22  	stdlib := slog.Stdlib(context.Background(), _default, slog.LevelInfo)
    23  	log.SetOutput(stdlib.Writer())
    24  }
    25  
    26  type loggerKey struct{}
    27  
    28  func from(ctx context.Context) slog.Logger {
    29  	l, ok := ctx.Value(loggerKey{}).(slog.Logger)
    30  	if !ok {
    31  		_default.Warn(ctx, "missing slog.Logger in context, see lib/log.With", slog.F("stack", string(debug.Stack())))
    32  		return _default
    33  	}
    34  	return l
    35  }
    36  
    37  func With(ctx context.Context, l slog.Logger) context.Context {
    38  	return context.WithValue(ctx, loggerKey{}, l)
    39  }
    40  
    41  // WithTB calls With with the result of slogtest.Make.
    42  func WithTB(ctx context.Context, t testing.TB, opts *slogtest.Options) context.Context {
    43  	l := slogtest.Make(t, opts)
    44  	if env.Debug() {
    45  		l = l.Leveled(slog.LevelDebug)
    46  	}
    47  	return With(ctx, l)
    48  }
    49  
    50  func Debug(ctx context.Context, msg string, fields ...slog.Field) {
    51  	slog.Helper()
    52  	from(ctx).Debug(ctx, msg, fields...)
    53  }
    54  
    55  func Info(ctx context.Context, msg string, fields ...slog.Field) {
    56  	slog.Helper()
    57  	from(ctx).Info(ctx, msg, fields...)
    58  }
    59  
    60  func Warn(ctx context.Context, msg string, fields ...slog.Field) {
    61  	slog.Helper()
    62  	from(ctx).Warn(ctx, msg, fields...)
    63  }
    64  
    65  func Error(ctx context.Context, msg string, fields ...slog.Field) {
    66  	slog.Helper()
    67  	from(ctx).Error(ctx, msg, fields...)
    68  }
    69  
    70  func Critical(ctx context.Context, msg string, fields ...slog.Field) {
    71  	slog.Helper()
    72  	from(ctx).Critical(ctx, msg, fields...)
    73  }
    74  
    75  func Fatal(ctx context.Context, msg string, fields ...slog.Field) {
    76  	slog.Helper()
    77  	from(ctx).Fatal(ctx, msg, fields...)
    78  }
    79  
    80  func Named(ctx context.Context, name string) context.Context {
    81  	return With(ctx, from(ctx).Named(name))
    82  }
    83  
    84  func Leveled(ctx context.Context, level slog.Level) context.Context {
    85  	return With(ctx, from(ctx).Leveled(level))
    86  }
    87  
    88  func AppendSinks(ctx context.Context, s ...slog.Sink) context.Context {
    89  	return With(ctx, from(ctx).AppendSinks(s...))
    90  }
    91  
    92  func Sync(ctx context.Context) {
    93  	from(ctx).Sync()
    94  }
    95  
    96  func Stdlib(ctx context.Context, level slog.Level) *log.Logger {
    97  	return slog.Stdlib(ctx, from(ctx), level)
    98  }
    99  
   100  func Fork(ctx, loggerCtx context.Context) context.Context {
   101  	return With(ctx, from(loggerCtx))
   102  }
   103  
   104  func Stderr(ctx context.Context) context.Context {
   105  	l := slog.Make(sloghuman.Sink(os.Stderr))
   106  	if os.Getenv("DEBUG") == "1" {
   107  		l = l.Leveled(slog.LevelDebug)
   108  	}
   109  
   110  	sl := slog.Stdlib(ctx, l, slog.LevelInfo)
   111  	stdlog.SetOutput(sl.Writer())
   112  
   113  	return With(ctx, l)
   114  }
   115  

View as plain text