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