Vibe-guided bskyoauth and custom repo example code in Golang 馃 probably not safe to use in prod
1package bskyoauth
2
3import (
4 "context"
5 "io"
6 "log/slog"
7 "os"
8 "strings"
9)
10
11// Logger is the package-level logger instance.
12// By default, logs are discarded. Call SetLogger() to enable logging.
13var Logger *slog.Logger = slog.New(slog.NewJSONHandler(io.Discard, nil))
14
15// SetLogger sets the package-level logger.
16// This should be called during application initialization to enable logging.
17//
18// Example:
19//
20// // Text logging to stdout (development)
21// handler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
22// Level: slog.LevelInfo,
23// })
24// bskyoauth.SetLogger(slog.New(handler))
25//
26// // JSON logging to stdout (production)
27// handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
28// Level: slog.LevelError,
29// })
30// bskyoauth.SetLogger(slog.New(handler))
31func SetLogger(logger *slog.Logger) {
32 if logger != nil {
33 Logger = logger
34 }
35}
36
37// NewDefaultLogger creates a default logger with JSON output to stdout.
38// Useful for quick setup without manual configuration.
39func NewDefaultLogger(level slog.Level) *slog.Logger {
40 return slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
41 Level: level,
42 }))
43}
44
45// NewTextLogger creates a text logger for development/debugging.
46func NewTextLogger(level slog.Level) *slog.Logger {
47 return slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
48 Level: level,
49 }))
50}
51
52// LogLevelFromEnv determines the appropriate log level based on environment.
53// Checks BASE_URL to determine if running locally or in production.
54// Returns Info level for localhost, Error level for production.
55func LogLevelFromEnv(baseURL string) slog.Level {
56 // Parse the base URL
57 if baseURL == "" {
58 return slog.LevelError // Default to production (Error level)
59 }
60
61 // Check if localhost
62 if strings.Contains(baseURL, "localhost") ||
63 strings.Contains(baseURL, "127.0.0.1") ||
64 strings.Contains(baseURL, "[::1]") {
65 return slog.LevelInfo // Development: Info level
66 }
67
68 return slog.LevelError // Production: Error level
69}
70
71// NewLoggerFromEnv creates a logger with appropriate settings based on environment.
72// Uses BASE_URL to determine if running locally (text, Info) or production (JSON, Error).
73//
74// Example:
75//
76// logger := bskyoauth.NewLoggerFromEnv(os.Getenv("BASE_URL"))
77// bskyoauth.SetLogger(logger)
78func NewLoggerFromEnv(baseURL string) *slog.Logger {
79 level := LogLevelFromEnv(baseURL)
80
81 // Localhost: use text format for readability
82 if strings.Contains(baseURL, "localhost") ||
83 strings.Contains(baseURL, "127.0.0.1") ||
84 strings.Contains(baseURL, "[::1]") {
85 return NewTextLogger(level)
86 }
87
88 // Production: use JSON format for log aggregation
89 return NewDefaultLogger(level)
90}
91
92// contextKey type for context values
93type contextKey string
94
95// WithRequestID adds a request ID to the context for correlation.
96func WithRequestID(ctx context.Context, requestID string) context.Context {
97 return context.WithValue(ctx, ContextKeyRequestID, requestID)
98}
99
100// WithSessionID adds a session ID to the context for correlation.
101func WithSessionID(ctx context.Context, sessionID string) context.Context {
102 return context.WithValue(ctx, ContextKeySessionID, sessionID)
103}
104
105// LoggerFromContext returns a logger with context values attached.
106// Extracts request_id and session_id from context if present.
107func LoggerFromContext(ctx context.Context) *slog.Logger {
108 logger := Logger
109
110 if requestID, ok := ctx.Value(ContextKeyRequestID).(string); ok && requestID != "" {
111 logger = logger.With("request_id", requestID)
112 }
113
114 if sessionID, ok := ctx.Value(ContextKeySessionID).(string); ok && sessionID != "" {
115 logger = logger.With("session_id", sessionID)
116 }
117
118 return logger
119}
120
121// GenerateRequestID generates a unique request ID for correlation.
122// Uses cryptographic randomness for uniqueness.
123func GenerateRequestID() string {
124 return GenerateSessionID() // Reuse session ID generation (already crypto-random)
125}