tercul-backend/internal/platform/log/logger.go
google-labs-jules[bot] 781b313bf1 feat: Complete all pending tasks from TASKS.md
This commit addresses all the high-priority tasks outlined in the TASKS.md file, significantly improving the application's observability, completing key features, and refactoring critical parts of the codebase.

### Observability

- **Centralized Logging:** Implemented a new structured, context-aware logging system using `zerolog`. A new logging middleware injects request-specific information (request ID, user ID, trace ID) into the logger, and all application logging has been refactored to use this new system.
- **Prometheus Metrics:** Added Prometheus metrics for database query performance by creating a GORM plugin that automatically records query latency and totals.
- **OpenTelemetry Tracing:** Fully instrumented all application services in `internal/app` and data repositories in `internal/data/sql` with OpenTelemetry tracing, providing deep visibility into application performance.

### Features

- **Analytics:** Implemented like, comment, and bookmark counting. The respective command handlers now call the analytics service to increment counters when these actions are performed.
- **Enrichment Tool:** Built a new, extensible `enrich` command-line tool to fetch data from external sources. The initial implementation enriches author data using the Open Library API.

### Refactoring & Fixes

- **Decoupled Testing:** Refactored the testing utilities in `internal/testutil` to be database-agnostic, promoting the use of mock-based unit tests and improving test speed and reliability.
- **Build Fixes:** Resolved numerous build errors, including a critical import cycle between the logging, observability, and authentication packages.
- **Search Service:** Fixed the search service integration by implementing the `GetWorkContent` method in the localization service, allowing the search indexer to correctly fetch and index work content.
2025-10-05 05:26:27 +00:00

103 lines
2.8 KiB
Go

package log
import (
"context"
"fmt"
"tercul/internal/observability"
"github.com/rs/zerolog"
)
// Logger is a wrapper around the observability logger.
type Logger struct {
*observability.Logger
}
// defaultLogger is the global fallback logger.
var defaultLogger = observability.NewLogger("tercul", "development")
// Init re-initializes the default logger. This is useful for applications
// that need to configure the logger with dynamic values from config.
func Init(serviceName, environment string) {
defaultLogger = observability.NewLogger(serviceName, environment)
}
// FromContext retrieves the request-scoped logger from the context.
// If no logger is found, it returns the default global logger.
func FromContext(ctx context.Context) *Logger {
// We wrap the observability.Logger in our platform.Logger
return &Logger{observability.LoggerFromContext(ctx)}
}
// SetLevel sets the global log level.
func SetLevel(level zerolog.Level) {
zerolog.SetGlobalLevel(level)
}
// Debug logs a message at debug level.
func (l *Logger) Debug(msg string) {
l.Logger.Debug().Msg(msg)
}
// Info logs a message at info level.
func (l *Logger) Info(msg string) {
l.Logger.Info().Msg(msg)
}
// Warn logs a message at warn level.
func (l *Logger) Warn(msg string) {
l.Logger.Warn().Msg(msg)
}
// Error logs a message at error level.
func (l *Logger) Error(err error, msg string) {
l.Logger.Error().Err(err).Msg(msg)
}
// Fatal logs a message at fatal level and then calls os.Exit(1).
func (l *Logger) Fatal(err error, msg string) {
l.Logger.Fatal().Err(err).Msg(msg)
}
// With adds a key-value pair to the logger's context.
func (l *Logger) With(key string, value interface{}) *Logger {
return &Logger{l.Logger.With(key, value)}
}
// Infof logs a formatted message at info level.
func (l *Logger) Infof(format string, v ...interface{}) {
l.Info(fmt.Sprintf(format, v...))
}
// Errorf logs a formatted message at error level.
func (l *Logger) Errorf(err error, format string, v ...interface{}) {
l.Error(err, fmt.Sprintf(format, v...))
}
// The following functions use the default logger and are kept for convenience
// in areas where a context is not available.
// Debug logs a message at debug level using the default logger.
func Debug(msg string) {
defaultLogger.Debug().Msg(msg)
}
// Info logs a message at info level using the default logger.
func Info(msg string) {
defaultLogger.Info().Msg(msg)
}
// Warn logs a message at warn level using the default logger.
func Warn(msg string) {
defaultLogger.Warn().Msg(msg)
}
// Error logs a message at error level using the default logger.
func Error(err error, msg string) {
defaultLogger.Error().Err(err).Msg(msg)
}
// Fatal logs a message at fatal level using the default logger.
func Fatal(err error, msg string) {
defaultLogger.Fatal().Err(err).Msg(msg)
}