# Structured Logger Package

A comprehensive structured logging package for Go applications with support for different log levels, service-specific logging, request context, and JSON output formatting.

## Features

- **Structured Logging**: JSON and text format output with rich metadata
- **Multiple Log Levels**: DEBUG, INFO, WARN, ERROR, FATAL
- **Service-Specific Logging**: Dedicated loggers for different services
- **Request Context**: Request ID and correlation ID tracking
- **Performance Timing**: Built-in duration logging for operations
- **Gin Middleware**: Request logging middleware for HTTP requests
- **Environment Configuration**: Configurable via environment variables

## Installation

The logger is already integrated into the project. Import it using:

```go
import "api-service/pkg/logger"
```

## Quick Start

### Basic Usage

```go
// Global functions (use default logger)
logger.Info("Application starting")
logger.Error("Something went wrong", map[string]interface{}{
    "error": err.Error(),
    "code":  "DB_CONNECTION_FAILED",
})

// Create a service-specific logger
authLogger := logger.ServiceLogger("auth-service")
authLogger.Info("User authenticated", map[string]interface{}{
    "user_id": "123",
    "method":  "oauth2",
})
```

### Service-Specific Loggers

```go
// Pre-defined service loggers
authLogger := logger.AuthServiceLogger()
bpjsLogger := logger.BPJSServiceLogger() 
retribusiLogger := logger.RetribusiServiceLogger()
databaseLogger := logger.DatabaseServiceLogger()

authLogger.Info("Authentication successful")
databaseLogger.Debug("Query executed", map[string]interface{}{
    "query": "SELECT * FROM users",
    "time":  "150ms",
})
```

### Request Context Logging

```go
// Add request context to logs
requestLogger := logger.Default().
    WithRequestID("req-123456").
    WithCorrelationID("corr-789012").
    WithField("user_id", "user-123")

requestLogger.Info("Request processing started", map[string]interface{}{
    "endpoint": "/api/v1/data",
    "method":   "POST",
})
```

### Performance Timing

```go
// Time operations and log duration
start := time.Now()
// ... perform operation ...
logger.LogDuration(start, "Database query completed", map[string]interface{}{
    "query":    "SELECT * FROM large_table",
    "rows":     1000,
    "database": "postgres",
})
```

## Gin Middleware Integration

### Add Request Logger Middleware

In your routes setup:

```go
import "api-service/pkg/logger"

func RegisterRoutes(cfg *config.Config) *gin.Engine {
    router := gin.New()
    
    // Add request logging middleware
    router.Use(logger.RequestLoggerMiddleware(logger.Default()))
    
    // ... other middleware and routes
    return router
}
```

### Access Logger in Handlers

```go
func (h *MyHandler) MyEndpoint(c *gin.Context) {
    // Get logger from context
    logger := logger.GetLoggerFromContext(c)
    
    logger.Info("Endpoint called", map[string]interface{}{
        "user_agent": c.Request.UserAgent(),
        "client_ip":  c.ClientIP(),
    })
    
    // Get request IDs
    requestID := logger.GetRequestIDFromContext(c)
    correlationID := logger.GetCorrelationIDFromContext(c)
}
```

## Configuration

### Environment Variables

Set these environment variables to configure the logger:

```bash
# Log level (DEBUG, INFO, WARN, ERROR, FATAL)
LOG_LEVEL=INFO

# Output format (text or json)
LOG_FORMAT=text

# Service name for logs
LOG_SERVICE=api-service

# Enable JSON format
LOG_JSON=false
```

### Programmatic Configuration

```go
// Create custom logger with specific configuration
cfg := logger.Config{
    Level:      "DEBUG",
    JSONFormat: true,
    Service:    "my-custom-service",
}

customLogger := logger.NewFromConfig(cfg)

// Or create manually
logger := logger.New("service-name", logger.DEBUG, true)
```

## Log Levels

| Level | Description | Usage |
|-------|-------------|-------|
| DEBUG | Detailed debug information | Development and troubleshooting |
| INFO | General operational messages | Normal application behavior |
| WARN | Warning conditions | Something unexpected but not an error |
| ERROR | Error conditions | Operation failed but application continues |
| FATAL | Critical conditions | Application cannot continue |

## Output Formats

### Text Format (Default)
```
2025-08-22T04:33:12+07:00 [INFO] auth-service: User authentication successful (handler/auth.go:45) [user_id=12345 method=oauth2]
```

### JSON Format
```json
{
  "timestamp": "2025-08-22T04:33:12+07:00",
  "level": "INFO",
  "service": "auth-service",
  "message": "User authentication successful",
  "file": "handler/auth.go",
  "line": 45,
  "request_id": "req-123456",
  "correlation_id": "corr-789012",
  "fields": {
    "user_id": "12345",
    "method": "oauth2"
  }
}
```

## Best Practices

### 1. Use Appropriate Log Levels
```go
// Good
logger.Debug("Detailed debug info")
logger.Info("User action completed")
logger.Warn("Rate limit approaching")
logger.Error("Database connection failed")

// Avoid
logger.Info("Error connecting to database") // Use ERROR instead
```

### 2. Add Context to Logs
```go
// Instead of this:
logger.Error("Login failed")

// Do this:
logger.Error("Login failed", map[string]interface{}{
    "username": username,
    "reason":   "invalid_credentials",
    "attempts": loginAttempts,
    "client_ip": clientIP,
})
```

### 3. Use Service-Specific Loggers
```go
// Create once per service
var authLogger = logger.AuthServiceLogger()

func LoginHandler(c *gin.Context) {
    authLogger.Info("Login attempt", map[string]interface{}{
        "username": c.PostForm("username"),
    })
}
```

### 4. Measure Performance
```go
func ProcessData(data []byte) error {
    start := time.Now()
    defer func() {
        logger.LogDuration(start, "Data processing completed", map[string]interface{}{
            "data_size": len(data),
            "items":     countItems(data),
        })
    }()
    
    // ... processing logic ...
}
```

## Migration from Standard Log Package

### Before (standard log)
```go
import "log"

log.Printf("Error: %v", err)
log.Printf("User %s logged in", username)
```

### After (structured logger)
```go
import "api-service/pkg/logger"

logger.Error("Operation failed", map[string]interface{}{
    "error": err.Error(),
    "context": "user_login",
})

logger.Info("User logged in", map[string]interface{}{
    "username": username,
    "method":   "password",
})
```

## Examples

### Database Operations
```go
func (h *UserHandler) GetUser(c *gin.Context) {
    logger := logger.GetLoggerFromContext(c)
    start := time.Now()
    
    user, err := h.db.GetUser(c.Param("id"))
    if err != nil {
        logger.Error("Failed to get user", map[string]interface{}{
            "user_id": c.Param("id"),
            "error":   err.Error(),
        })
        c.JSON(500, gin.H{"error": "Internal server error"})
        return
    }
    
    logger.LogDuration(start, "User retrieved successfully", map[string]interface{}{
        "user_id": user.ID,
        "query_time": time.Since(start).String(),
    })
    
    c.JSON(200, user)
}
```

### Authentication Service
```go
var authLogger = logger.AuthServiceLogger()

func Authenticate(username, password string) (bool, error) {
    authLogger.Debug("Authentication attempt", map[string]interface{}{
        "username": username,
    })
    
    // Authentication logic...
    
    if authenticated {
        authLogger.Info("Authentication successful", map[string]interface{}{
            "username": username,
            "method":   "password",
        })
        return true, nil
    }
    
    authLogger.Warn("Authentication failed", map[string]interface{}{
        "username": username,
        "reason":   "invalid_credentials",
    })
    return false, nil
}
```

## Troubleshooting

### Common Issues

1. **No logs appearing**: Check that log level is not set too high (e.g., ERROR when logging INFO)
2. **JSON format not working**: Ensure `LOG_JSON=true` or logger is created with `jsonFormat: true`
3. **Missing context**: Use `WithRequestID()` and `WithCorrelationID()` for request context

### Debug Mode

Enable debug logging for development:

```bash
export LOG_LEVEL=DEBUG
export LOG_FORMAT=text
```

## Performance Considerations

- Logger is designed to be lightweight and fast
- Context fields are only evaluated when the log level is enabled
- JSON marshaling only occurs when JSON format is enabled
- Consider log volume in production environments

## License

This logger package is part of the API Service project.
