Skip to content

Commit 8d3b7ba

Browse files
committed
feat: improved the logging system to enable troubleshooting of OAuth2 errors:
- Added structured logs in HandleError() for each error type in middleware - Explicit log of the OAuth callback error before handling feat: add configurable log level via ACKIFY_LOG_LEVEL - Add ParseLevel function to logger package - Extend config structure with LoggerConfig - Apply log level during server initialization - Update documentation and .env.example
1 parent dbe43a4 commit 8d3b7ba

File tree

9 files changed

+49
-4
lines changed

9 files changed

+49
-4
lines changed

.env.example

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ APP_NAME=ackify
33
APP_DNS=sign.your-domain.com
44
ACKIFY_BASE_URL=https://sign.your-domain.com
55
ACKIFY_ORGANISATION="Your Organization Name"
6+
ACKIFY_LOG_LEVEL=info
67

78
# Database Configuration
89
POSTGRES_USER=ackifyr

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,11 @@ ACKIFY_OAUTH_SCOPES="read:user,user:email"
173173
ACKIFY_OAUTH_ALLOWED_DOMAIN="@company.com" # Only @company.com emails
174174
```
175175

176+
### Log level setup
177+
```bash
178+
ACKIFY_LOG_LEVEL="info" # can be debug, info, warn(ing), error. default: info
179+
```
180+
176181
---
177182

178183
## 🛡️ Security & Architecture

README_FR.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,11 @@ ACKIFY_OAUTH_SCOPES="read:user,user:email"
181181
ACKIFY_OAUTH_ALLOWED_DOMAIN="@entreprise.com" # Seuls les emails @entreprise.com
182182
```
183183

184+
### Log level setup
185+
```bash
186+
ACKIFY_LOG_LEVEL="info" # can be debug, info, warn(ing), error. default: info
187+
```
188+
184189
---
185190

186191
## 🛡️ Sécurité & Architecture

cmd/community/main.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ func main() {
2222
log.Fatalf("Failed to create server: %v", err)
2323
}
2424

25-
// Register admin routes (reuse server DB connection)
2625
server.RegisterRoutes(admin.RegisterAdminRoutes(server.GetBaseURL(), server.GetTemplates(), server.GetDB()))
2726

2827
go func() {

internal/infrastructure/config/config.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type Config struct {
1515
Database DatabaseConfig
1616
OAuth OAuthConfig
1717
Server ServerConfig
18+
Logger LoggerConfig
1819
}
1920

2021
type AppConfig struct {
@@ -42,6 +43,10 @@ type ServerConfig struct {
4243
ListenAddr string
4344
}
4445

46+
type LoggerConfig struct {
47+
Level string
48+
}
49+
4550
// Load loads configuration from environment variables
4651
func Load() (*Config, error) {
4752
config := &Config{}
@@ -91,6 +96,8 @@ func Load() (*Config, error) {
9196

9297
config.Server.ListenAddr = getEnv("ACKIFY_LISTEN_ADDR", ":8080")
9398

99+
config.Logger.Level = getEnv("ACKIFY_LOG_LEVEL", "info")
100+
94101
return config, nil
95102
}
96103

internal/presentation/handlers/auth.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"net/http"
66
"net/url"
77
"strings"
8+
9+
"github.com/btouchard/ackify-ce/pkg/logger"
810
)
911

1012
type AuthHandlers struct {
@@ -58,6 +60,7 @@ func (h *AuthHandlers) HandleOAuthCallback(w http.ResponseWriter, r *http.Reques
5860
ctx := r.Context()
5961
user, nextURL, err := h.authService.HandleCallback(ctx, code, state)
6062
if err != nil {
63+
logger.Logger.Error("OAuth callback failed", "error", err.Error())
6164
HandleError(w, err)
6265
return
6366
}

internal/presentation/handlers/middleware.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,20 +85,28 @@ type ErrorResponse struct {
8585
func HandleError(w http.ResponseWriter, err error) {
8686
switch {
8787
case errors.Is(err, models.ErrUnauthorized):
88+
logger.Logger.Warn("Unauthorized access attempt", "error", err.Error())
8889
http.Error(w, "Unauthorized", http.StatusUnauthorized)
8990
case errors.Is(err, models.ErrSignatureNotFound):
91+
logger.Logger.Debug("Signature not found", "error", err.Error())
9092
http.Error(w, "Signature not found", http.StatusNotFound)
9193
case errors.Is(err, models.ErrSignatureAlreadyExists):
94+
logger.Logger.Debug("Duplicate signature attempt", "error", err.Error())
9295
http.Error(w, "Signature already exists", http.StatusConflict)
9396
case errors.Is(err, models.ErrInvalidUser):
97+
logger.Logger.Warn("Invalid user data", "error", err.Error())
9498
http.Error(w, "Invalid user", http.StatusBadRequest)
9599
case errors.Is(err, models.ErrInvalidDocument):
100+
logger.Logger.Warn("Invalid document ID", "error", err.Error())
96101
http.Error(w, "Invalid document ID", http.StatusBadRequest)
97102
case errors.Is(err, models.ErrDomainNotAllowed):
103+
logger.Logger.Warn("Domain not allowed", "error", err.Error())
98104
http.Error(w, "Domain not allowed", http.StatusForbidden)
99105
case errors.Is(err, models.ErrDatabaseConnection):
106+
logger.Logger.Error("Database connection error", "error", err.Error())
100107
http.Error(w, "Database error", http.StatusInternalServerError)
101108
default:
109+
logger.Logger.Error("Unhandled error", "error", err.Error())
102110
http.Error(w, "Internal server error", http.StatusInternalServerError)
103111
}
104112
}

pkg/logger/logger.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,32 @@ package logger
44
import (
55
"log/slog"
66
"os"
7+
"strings"
78
)
89

910
var Logger *slog.Logger
1011

1112
func init() {
12-
Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
13-
Level: slog.LevelInfo,
14-
}))
13+
SetLevel(slog.LevelInfo)
1514
}
1615

1716
func SetLevel(level slog.Level) {
1817
Logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
1918
Level: level,
2019
}))
2120
}
21+
22+
func ParseLevel(levelStr string) slog.Level {
23+
switch strings.ToLower(strings.TrimSpace(levelStr)) {
24+
case "debug":
25+
return slog.LevelDebug
26+
case "info":
27+
return slog.LevelInfo
28+
case "warn", "warning":
29+
return slog.LevelWarn
30+
case "error":
31+
return slog.LevelError
32+
default:
33+
return slog.LevelInfo
34+
}
35+
}

pkg/web/server.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"os"
1111
"path/filepath"
1212

13+
"github.com/btouchard/ackify-ce/pkg/logger"
1314
"github.com/go-chi/chi/v5"
1415

1516
"github.com/btouchard/ackify-ce/internal/application/services"
@@ -34,6 +35,8 @@ func NewServer(ctx context.Context) (*Server, error) {
3435
return nil, fmt.Errorf("failed to initialize infrastructure: %w", err)
3536
}
3637

38+
logger.SetLevel(logger.ParseLevel(cfg.Logger.Level))
39+
3740
authService := auth.NewOAuthService(auth.Config{
3841
BaseURL: cfg.App.BaseURL,
3942
ClientID: cfg.OAuth.ClientID,

0 commit comments

Comments
 (0)