Scaffolds the server module and everything Phase 0 of PLAN.md calls for: a binary that boots, serves its discovery endpoints and nothing else yet. - config: one YAML file plus per-field WARP_* environment overrides, unknown fields rejected, validation that reports every problem at once - logging and metrics: slog, a Prometheus registry, per-route HTTP instrumentation labelled by pattern rather than path - httputil: the Matrix error envelope, error-returning handlers, CORS, request logging, panic recovery, and a router over http.ServeMux - endpoints: /_matrix/client/versions, /.well-known/matrix/client, /.well-known/matrix/server (gated), /healthz, /metrics, and M_UNRECOGNIZED for everything else - storage: driver registry, shared database/sql base, checksummed migration runner, sqlite and postgres drivers, pocketbase stub - settings: server_settings table behind a cached service, so the federation and registration switches change without a restart - federation: the gate that makes federation a runtime mode - cmd/warp: serve, migrate, generate-keys, version - Makefile, golangci-lint v2, GitHub Actions CI (Linux and Windows tests, race on Linux, storage tests against PostgreSQL, lint, boot smoke test), Dockerfile, example config and docs Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
53 lines
1.2 KiB
Go
53 lines
1.2 KiB
Go
// Package logging configures the process-wide slog logger.
|
|
package logging
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"log/slog"
|
|
"strings"
|
|
)
|
|
|
|
// Options mirrors the logging section of the config file.
|
|
type Options struct {
|
|
Level string
|
|
Format string
|
|
AddSource bool
|
|
}
|
|
|
|
// ParseLevel maps a config string onto a slog level.
|
|
func ParseLevel(s string) (slog.Level, error) {
|
|
switch strings.ToLower(strings.TrimSpace(s)) {
|
|
case "debug":
|
|
return slog.LevelDebug, nil
|
|
case "", "info":
|
|
return slog.LevelInfo, nil
|
|
case "warn", "warning":
|
|
return slog.LevelWarn, nil
|
|
case "error":
|
|
return slog.LevelError, nil
|
|
default:
|
|
return 0, fmt.Errorf("unknown log level %q", s)
|
|
}
|
|
}
|
|
|
|
// New builds a logger writing to w. It does not install it as the default.
|
|
func New(w io.Writer, opts Options) (*slog.Logger, error) {
|
|
level, err := ParseLevel(opts.Level)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
handlerOpts := &slog.HandlerOptions{Level: level, AddSource: opts.AddSource}
|
|
|
|
var h slog.Handler
|
|
switch strings.ToLower(strings.TrimSpace(opts.Format)) {
|
|
case "", "text":
|
|
h = slog.NewTextHandler(w, handlerOpts)
|
|
case "json":
|
|
h = slog.NewJSONHandler(w, handlerOpts)
|
|
default:
|
|
return nil, fmt.Errorf("unknown log format %q", opts.Format)
|
|
}
|
|
return slog.New(h), nil
|
|
}
|