package gobang import ( "crypto/rand" "errors" "fmt" "io" "log/slog" "math/big" "os" "reflect" "runtime" "runtime/debug" "slices" "strings" "syscall" "time" "guuid" ) type LogLevel int8 const ( LevelNone LogLevel = 0 LevelError LogLevel = 1 LevelWarning LogLevel = 2 LevelInfo LogLevel = 3 LevelDebug LogLevel = 4 ) type Gauge struct { Inc func(...any) Dec func(...any) } type CopyResult struct { Written int64 Err error Label string } const maxInt = int((^uint(0)) >> 1) const MinimumPasswordLength = 16 // Local variables var ( level LogLevel = LevelInfo emitMetric bool = true hostname string Version = version ) func SomeError(errs []error) error { for _, err := range errs { if err != nil { return err } } return nil } func SomeFnError(fns [](func() error)) error { errs := make([]error, len(fns)) for i, fn := range fns { errs[i] = fn() } return SomeError(errs) } func Random(length int) []byte { buffer := make([]byte, length) _, err := io.ReadFull(rand.Reader, buffer) FatalIf(err) return buffer } func sourceInfo(skip int) slog.Attr { pc := make([]uintptr, 10) n := runtime.Callers(skip, pc) if n == 0 { return slog.Group( "src", "file", "UNAVAILABLE", "function", "UNAVAILABLE", "line", "UNAVAILABLE", ) } pc = pc[:n] frames := runtime.CallersFrames(pc) frame, _ := frames.Next() return slog.Group( "src", "file", frame.File, "function", frame.Function, "line", frame.Line, ) } func logArgs(type_ string) []string { return []string { "id", guuid.New().String(), "kind", "log", "type", type_, } } func anyArr[S ~[]E, E any](arr S) []any { ret := make([]any, len(arr)) for i , el := range arr { ret[i] = el } return ret } func Debug(message string, type_ string, args ...any) { if level < LevelDebug { return } slog.Debug( message, slices.Concat( anyArr(logArgs(type_)), []any { sourceInfo(3) }, args, )..., ) } func Info(message string, type_ string, args ...any) { if level < LevelInfo { return } slog.Info( message, slices.Concat( anyArr(logArgs(type_)), []any { sourceInfo(3) }, args, )..., ) } func Warning(message string, type_ string, args ...any) { if level < LevelWarning { return } slog.Warn( message, slices.Concat( anyArr(logArgs(type_)), []any { sourceInfo(3) }, args, )..., ) } func Error(message string, type_ string, args ...any) { if level < LevelError { return } slog.Error( message, slices.Concat( anyArr(logArgs(type_)), []any { sourceInfo(3) }, args, )..., ) } func metric(type_ string, label string, args ...any) { if !emitMetric { return } slog.Info( "_", slices.Concat( []any { "id", guuid.New().String(), "kind", "metric", "type", type_, "label", label, }, []any { sourceInfo(3) }, args, )..., ) } func Timed(label string, thunk func(), args ...any) { var ( start time.Time end time.Time ) { start = time.Now() thunk() end = time.Now() } duration := end.Sub(start) metric( "timer", label, slices.Concat( []any{ "start", start, "end", end, "duration", duration, }, args, )..., ) } func MakeCounter(label string, staticArgs ...any) func(...any) { return func(dynamicArgs ...any) { metric( "counter", label, slices.Concat( []any { "value", 1 }, staticArgs, dynamicArgs, )..., ) } } func MakeGauge(label string, staticArgs ...any) Gauge { var zero = big.NewInt(0) var one = big.NewInt(1) count := big.NewInt(0) emitGauge := func(dynamicArgs ...any) { if count.Cmp(zero) == -1 { Error( "Gauge went negative", "process-metric", slices.Concat( []any { "value", count }, staticArgs, dynamicArgs, )..., ) return // avoid wrong metrics being emitted } metric( "gauge", label, slices.Concat( []any { "value", count }, staticArgs, dynamicArgs, )..., ) } return Gauge { Inc: func(dynamicArgs ...any) { count.Add(count, one) emitGauge(dynamicArgs...) }, Dec: func(dynamicArgs ...any) { count.Sub(count, one) emitGauge(dynamicArgs...) }, } } func ErrorIf(err error) { if err != nil { fmt.Fprintf(os.Stderr, "Unexpected error: %#v\n", err) os.Exit(1) } } func ErrorNil(err error) { if err == nil { fmt.Fprintf(os.Stderr, "Expected error, got nil\n") os.Exit(1) } } func showColour() bool { return os.Getenv("NO_COLOUR") == "" } func TestStart(name string) { fmt.Fprintf(os.Stderr, "%s:\n", name) } func Testing(message string, body func()) { if showColour() { fmt.Fprintf( os.Stderr, "\033[0;33mtesting\033[0m: %s... ", message, ) body() fmt.Fprint(os.Stderr, "\033[0;32mOK\033[0m.\n") } else { fmt.Fprintf(os.Stderr, "testing: %s...", message) body() fmt.Fprint(os.Stderr, " OK.\n") } } func AssertEqual(given any, expected any) { if !reflect.DeepEqual(given, expected) { if showColour() { fmt.Fprintf(os.Stderr, "\033[0;31mERR\033[0m.\n") } else { fmt.Fprintf(os.Stderr, "ERR.\n") } fmt.Fprintf(os.Stderr, "given != expected\n") fmt.Fprintf(os.Stderr, "given: %#v\n", given) fmt.Fprintf(os.Stderr, "expected: %#v\n", expected) os.Exit(1) } } func AssertEqualI(i int, given any, expected any) { if !reflect.DeepEqual(given, expected) { if showColour() { fmt.Fprintf(os.Stderr, "\033[0;31mERR\033[0m.\n") } else { fmt.Fprintf(os.Stderr, "ERR.\n") } fmt.Fprintf(os.Stderr, "given != expected (i = %d)\n", i) fmt.Fprintf(os.Stderr, "given: %#v\n", given) fmt.Fprintf(os.Stderr, "expected: %#v\n", expected) os.Exit(1) } } var unfilteringLevel = new(slog.LevelVar) func SetLoggerOutput(w io.Writer, args ...any) { unfilteringLevel.Set(slog.LevelDebug) slog.SetDefault(slog.New(slog.NewJSONHandler(w, &slog.HandlerOptions { Level: unfilteringLevel, })).With( slog.Group( "info", "pid", os.Getpid(), "ppid", os.Getppid(), "puuid", guuid.New().String(), ), ).With(args...)) } func levelFromString(name string, fallback LogLevel) LogLevel { switch strings.ToUpper(name) { case "NONE": return LevelNone case "ERROR": return LevelError case "WARNING": return LevelWarning case "INFO": return LevelInfo case "DEBUG": return LevelDebug default: return fallback } } func setLogLevel() { level = levelFromString(os.Getenv("LOG_LEVEL"), level) } func SetLevel(l LogLevel) { level = l } func setMetric() { if os.Getenv("NO_METRIC") != "" { emitMetric = false } } func setTraceback() { if os.Getenv("GOTRACEBACK") == "" { debug.SetTraceback("crash") } } func Fatal(err error) { Error( "Fatal error", "fatal-error", "error", err, "stack", string(debug.Stack()), ) syscall.Kill(os.Getpid(), syscall.SIGABRT) os.Exit(3) } func FatalIf(err error) { if err != nil { Fatal(err) } } func Assert(condition bool, message string) { if !condition { Fatal(errors.New(message)) } } func Unreachable() { Assert(false, "Unreachable code was reached") } func setHostname() { var err error hostname, err = os.Hostname() FatalIf(err) } func Init(args ...any) { SetLoggerOutput(os.Stdout, args...) setLogLevel() setMetric() setTraceback() setHostname() }