Files
Test 59a1eeed85 feat(T1.2): implement structured logging and Prometheus metrics
- Add internal/logging package with zap-based structured JSON logging
- Support development (colored) and production (JSON) modes via ENVIRONMENT env var
- Add logging helpers: Info(), Error(), Warn(), Debug(), Fatal()
- Add field helpers: String(), Int(), Int64(), Err()
- Add internal/metrics package with 16 comprehensive Prometheus metrics
- Track workflows: starts, completions, duration by type/status
- Track activities: starts, completions, duration, retries by type
- Track LLM calls: total calls and latency by model
- Track git operations: total and duration by operation type
- Track judge decisions: decisions by type
- Track Temporal errors: connection errors by type
- Track cache efficiency: hits and misses by cache type
- Track tasks in progress: gauge metric by task type
- Metrics exported on /metrics endpoint (Prometheus text format)
- Integrate structured logging in cmd/worker and cmd/starter
- Replace all log.Printf/log.Fatalf with structured logging
- Add /metrics endpoint to health check server
- 8/8 logging tests passing, 13/13 metrics tests passing
- All verification criteria met

Dependencies added:
- go.uber.org/zap v1.28.0 (structured logging)
- github.com/prometheus/client_golang v1.24.1 (metrics export)

Closes T1.2
2026-08-23 16:33:49 -07:00

98 lines
2.0 KiB
Go

package logging
import (
"os"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
var logger *zap.Logger
// InitLogger initializes the global logger
func InitLogger() error {
var config zap.Config
// Use pretty config in development, JSON in production
if os.Getenv("ENVIRONMENT") == "production" {
config = zap.NewProductionConfig()
} else {
config = zap.NewDevelopmentConfig()
config.EncoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
}
var err error
logger, err = config.Build()
if err != nil {
return err
}
return nil
}
// GetLogger returns the global logger
func GetLogger() *zap.Logger {
if logger == nil {
logger, _ = zap.NewProduction()
}
return logger
}
// Info logs an info message
func Info(message string, fields ...zap.Field) {
GetLogger().Info(message, fields...)
}
// Error logs an error message
func Error(message string, fields ...zap.Field) {
GetLogger().Error(message, fields...)
}
// Warn logs a warning message
func Warn(message string, fields ...zap.Field) {
GetLogger().Warn(message, fields...)
}
// Debug logs a debug message
func Debug(message string, fields ...zap.Field) {
GetLogger().Debug(message, fields...)
}
// Fatal logs a fatal message and exits
func Fatal(message string, fields ...zap.Field) {
GetLogger().Fatal(message, fields...)
}
// Sync flushes any buffered log entries
func Sync() error {
if logger != nil {
return logger.Sync()
}
return nil
}
// With returns a child logger with additional fields
func With(fields ...zap.Field) *zap.Logger {
return GetLogger().With(fields...)
}
// String is a helper for creating a string field
func String(key, value string) zap.Field {
return zap.String(key, value)
}
// Int is a helper for creating an int field
func Int(key string, value int) zap.Field {
return zap.Int(key, value)
}
// Int64 is a helper for creating an int64 field
func Int64(key string, value int64) zap.Field {
return zap.Int64(key, value)
}
// Error field helper
func Err(err error) zap.Field {
return zap.Error(err)
}