feature/epic1-core-infrastructure #2
@@ -18,3 +18,9 @@ logging:
|
||||
level: "info"
|
||||
format: "json"
|
||||
output: "stdout"
|
||||
|
||||
tracing:
|
||||
enabled: true
|
||||
service_name: "platform"
|
||||
service_version: "1.0.0"
|
||||
otlp_endpoint: ""
|
||||
|
||||
30
docker-compose.yml
Normal file
30
docker-compose.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: goplt-postgres
|
||||
environment:
|
||||
POSTGRES_USER: goplt
|
||||
POSTGRES_PASSWORD: goplt_password
|
||||
POSTGRES_DB: goplt
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U goplt"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- goplt-network
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
goplt-network:
|
||||
driver: bridge
|
||||
|
||||
@@ -43,8 +43,8 @@ All architectural decisions are documented in [ADR records](adr/README.md), orga
|
||||
|
||||
### 📝 Implementation Tasks
|
||||
Detailed task definitions for each epic are available in the [Stories section](stories/README.md):
|
||||
- Epic 0: Project Setup & Foundation
|
||||
- Epic 1: Core Kernel & Infrastructure
|
||||
- **[Epic 0: Project Setup & Foundation](stories/epic0/README.md)** - [Implementation Summary](stories/epic0/SUMMARY.md)
|
||||
- **[Epic 1: Core Kernel & Infrastructure](stories/epic1/README.md)** - [Implementation Summary](stories/epic1/SUMMARY.md)
|
||||
- Epic 2: Authentication & Authorization
|
||||
- Epic 3: Module Framework
|
||||
- Epic 4: Sample Feature Module (Blog)
|
||||
|
||||
@@ -44,3 +44,7 @@ Initialize repository structure with proper Go project layout, implement configu
|
||||
- Config loads from `config/default.yaml`
|
||||
- Logger can be injected and used
|
||||
- Application starts and shuts down gracefully
|
||||
|
||||
## Implementation Summary
|
||||
|
||||
- [Implementation Summary and Verification Instructions](./SUMMARY.md) - Complete guide on how to verify all Epic 0 functionality
|
||||
|
||||
152
docs/content/stories/epic0/SUMMARY.md
Normal file
152
docs/content/stories/epic0/SUMMARY.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# Epic 0: Implementation Summary
|
||||
|
||||
## Overview
|
||||
|
||||
Epic 0 establishes the foundation of the Go Platform project with core infrastructure components that enable all future development. This epic includes project initialization, configuration management, structured logging, CI/CD pipeline, and dependency injection setup.
|
||||
|
||||
## Completed Stories
|
||||
|
||||
### ✅ 0.1 Project Initialization
|
||||
- Go module initialized with proper module path
|
||||
- Complete directory structure following Clean Architecture
|
||||
- `.gitignore` configured for Go projects
|
||||
- Comprehensive README with project overview
|
||||
|
||||
### ✅ 0.2 Configuration Management System
|
||||
- `ConfigProvider` interface in `pkg/config/`
|
||||
- Viper-based implementation in `internal/config/`
|
||||
- YAML configuration files in `config/` directory
|
||||
- Environment variable support with automatic mapping
|
||||
- Type-safe configuration access methods
|
||||
|
||||
### ✅ 0.3 Structured Logging System
|
||||
- `Logger` interface in `pkg/logger/`
|
||||
- Zap-based implementation in `internal/logger/`
|
||||
- JSON and console output formats
|
||||
- Configurable log levels
|
||||
- Request ID and context-aware logging support
|
||||
|
||||
### ✅ 0.4 CI/CD Pipeline
|
||||
- GitHub Actions workflow for automated testing and linting
|
||||
- Comprehensive Makefile with common development tasks
|
||||
- Automated build and test execution
|
||||
|
||||
### ✅ 0.5 Dependency Injection and Bootstrap
|
||||
- DI container using Uber FX in `internal/di/`
|
||||
- Provider functions for core services
|
||||
- Application entry point in `cmd/platform/main.go`
|
||||
- Lifecycle management with graceful shutdown
|
||||
|
||||
## Verification Instructions
|
||||
|
||||
### Prerequisites
|
||||
- Go 1.24 or later installed
|
||||
- Make installed (optional, for using Makefile commands)
|
||||
|
||||
### 1. Verify Project Structure
|
||||
|
||||
```bash
|
||||
# Check Go module
|
||||
go mod verify
|
||||
|
||||
# Check directory structure
|
||||
ls -la
|
||||
# Should see: cmd/, internal/, pkg/, config/, docs/, etc.
|
||||
```
|
||||
|
||||
### 2. Verify Configuration System
|
||||
|
||||
```bash
|
||||
# Build the application
|
||||
go build ./cmd/platform
|
||||
|
||||
# Check if config files exist
|
||||
ls -la config/
|
||||
# Should see: default.yaml, development.yaml, production.yaml
|
||||
|
||||
# Test config loading (will fail without database, but config should load)
|
||||
# This will be tested in Epic 1 when database is available
|
||||
```
|
||||
|
||||
### 3. Verify Logging System
|
||||
|
||||
```bash
|
||||
# Run tests for logging
|
||||
go test ./internal/logger/...
|
||||
|
||||
# Expected output: Tests should pass
|
||||
```
|
||||
|
||||
### 4. Verify CI/CD Pipeline
|
||||
|
||||
```bash
|
||||
# Run linting (if golangci-lint is installed)
|
||||
make lint
|
||||
|
||||
# Run tests
|
||||
make test
|
||||
|
||||
# Build the application
|
||||
make build
|
||||
# Binary should be created in bin/platform
|
||||
|
||||
# Run all checks
|
||||
make check
|
||||
```
|
||||
|
||||
### 5. Verify Dependency Injection
|
||||
|
||||
```bash
|
||||
# Build the application
|
||||
go build ./cmd/platform
|
||||
|
||||
# Check if DI container compiles
|
||||
go build ./internal/di/...
|
||||
|
||||
# Run the application (will fail without database in Epic 1)
|
||||
# go run ./cmd/platform/main.go
|
||||
```
|
||||
|
||||
### 6. Verify Application Bootstrap
|
||||
|
||||
```bash
|
||||
# Build the application
|
||||
make build
|
||||
|
||||
# Check if binary exists
|
||||
ls -la bin/platform
|
||||
|
||||
# The application should be ready to run (database connection will be tested in Epic 1)
|
||||
```
|
||||
|
||||
## Testing Configuration
|
||||
|
||||
The configuration system can be tested by:
|
||||
|
||||
1. **Modifying config files**: Edit `config/default.yaml` and verify changes are loaded
|
||||
2. **Environment variables**: Set `ENVIRONMENT=production` and verify production config is loaded
|
||||
3. **Type safety**: Configuration access methods (`GetString`, `GetInt`, etc.) provide compile-time safety
|
||||
|
||||
## Testing Logging
|
||||
|
||||
The logging system can be tested by:
|
||||
|
||||
1. **Unit tests**: Run `go test ./internal/logger/...`
|
||||
2. **Integration**: Logging will be tested in Epic 1 when HTTP server is available
|
||||
3. **Format switching**: Change `logging.format` in config to switch between JSON and console output
|
||||
|
||||
## Common Issues and Solutions
|
||||
|
||||
### Issue: `go mod verify` fails
|
||||
**Solution**: Run `go mod tidy` to update dependencies
|
||||
|
||||
### Issue: Build fails
|
||||
**Solution**: Ensure Go 1.24+ is installed and all dependencies are downloaded (`go mod download`)
|
||||
|
||||
### Issue: Config not loading
|
||||
**Solution**: Ensure `config/default.yaml` exists and is in the correct location relative to the binary
|
||||
|
||||
## Next Steps
|
||||
|
||||
After verifying Epic 0, proceed to [Epic 1](../epic1/SUMMARY.md) to set up the database and HTTP server, which will enable full end-to-end testing of the configuration and logging systems.
|
||||
|
||||
@@ -56,3 +56,7 @@ Extend DI container to support all core services, implement database layer with
|
||||
- Panic recovery logs errors via error bus
|
||||
- Database migrations run on startup
|
||||
- HTTP requests are traced with OpenTelemetry
|
||||
|
||||
## Implementation Summary
|
||||
|
||||
- [Implementation Summary and Verification Instructions](./SUMMARY.md) - Complete guide on how to verify all Epic 1 functionality, including database testing and Docker Compose setup
|
||||
|
||||
402
docs/content/stories/epic1/SUMMARY.md
Normal file
402
docs/content/stories/epic1/SUMMARY.md
Normal file
@@ -0,0 +1,402 @@
|
||||
# Epic 1: Implementation Summary
|
||||
|
||||
## Overview
|
||||
|
||||
Epic 1 implements the core kernel and infrastructure of the Go Platform, including database layer with Ent ORM, health monitoring, metrics, error handling, HTTP server, and OpenTelemetry tracing. This epic provides the foundation for all future modules and services.
|
||||
|
||||
## Completed Stories
|
||||
|
||||
### ✅ 1.1 Enhanced Dependency Injection Container
|
||||
- Extended DI container with providers for all core services
|
||||
- Database, health, metrics, error bus, and HTTP server providers
|
||||
- Lifecycle management for all services
|
||||
- `CoreModule()` exports all core services
|
||||
|
||||
### ✅ 1.2 Database Layer with Ent ORM
|
||||
- Ent schema for User, Role, Permission, AuditLog entities
|
||||
- Many-to-many relationships (User-Role, Role-Permission)
|
||||
- Database client wrapper with connection pooling
|
||||
- Automatic migrations on startup
|
||||
- PostgreSQL support with connection management
|
||||
|
||||
### ✅ 1.3 Health Monitoring and Metrics System
|
||||
- Health check registry with extensible checkers
|
||||
- Database health checker
|
||||
- Prometheus metrics with HTTP instrumentation
|
||||
- `/healthz`, `/ready`, and `/metrics` endpoints
|
||||
|
||||
### ✅ 1.4 Error Handling and Error Bus
|
||||
- Channel-based error bus with background consumer
|
||||
- ErrorPublisher interface
|
||||
- Panic recovery middleware
|
||||
- Error context preservation
|
||||
|
||||
### ✅ 1.5 HTTP Server Foundation
|
||||
- Gin-based HTTP server
|
||||
- Comprehensive middleware stack:
|
||||
- Request ID generation
|
||||
- Structured logging
|
||||
- Panic recovery with error bus
|
||||
- Prometheus metrics
|
||||
- CORS support
|
||||
- Core routes registration
|
||||
- Graceful shutdown
|
||||
|
||||
### ✅ 1.6 OpenTelemetry Distributed Tracing
|
||||
- Tracer initialization with stdout (dev) and OTLP (prod) exporters
|
||||
- HTTP request instrumentation
|
||||
- Trace ID correlation in logs
|
||||
- Configurable tracing
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before verifying Epic 1, ensure you have:
|
||||
|
||||
1. **Docker and Docker Compose** installed
|
||||
2. **PostgreSQL client** (optional, for direct database access)
|
||||
3. **Go 1.24+** installed
|
||||
4. **curl** or similar HTTP client for testing endpoints
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
### 1. Start PostgreSQL Database
|
||||
|
||||
The project includes a `docker-compose.yml` file for easy database setup:
|
||||
|
||||
```bash
|
||||
# Start PostgreSQL container
|
||||
docker-compose up -d postgres
|
||||
|
||||
# Verify container is running
|
||||
docker-compose ps
|
||||
|
||||
# Check database logs
|
||||
docker-compose logs postgres
|
||||
```
|
||||
|
||||
The database will be available at:
|
||||
- **Host**: `localhost`
|
||||
- **Port**: `5432`
|
||||
- **Database**: `goplt`
|
||||
- **User**: `goplt`
|
||||
- **Password**: `goplt_password`
|
||||
|
||||
### 2. Configure Database Connection
|
||||
|
||||
Update `config/default.yaml` or set environment variable:
|
||||
|
||||
```bash
|
||||
# Option 1: Edit config/default.yaml
|
||||
# Set database.dsn to:
|
||||
database:
|
||||
dsn: "postgres://goplt:goplt_password@localhost:5432/goplt?sslmode=disable"
|
||||
|
||||
# Option 2: Set environment variable
|
||||
export DATABASE_DSN="postgres://goplt:goplt_password@localhost:5432/goplt?sslmode=disable"
|
||||
```
|
||||
|
||||
### 3. Build and Run the Application
|
||||
|
||||
```bash
|
||||
# Build the application
|
||||
make build
|
||||
|
||||
# Or build directly
|
||||
go build -o bin/platform ./cmd/platform
|
||||
|
||||
# Run the application
|
||||
./bin/platform
|
||||
|
||||
# Or run directly
|
||||
go run ./cmd/platform/main.go
|
||||
```
|
||||
|
||||
The application will:
|
||||
1. Load configuration
|
||||
2. Initialize logger
|
||||
3. Connect to database
|
||||
4. Run migrations (create tables)
|
||||
5. Start HTTP server on port 8080
|
||||
|
||||
## Verification Instructions
|
||||
|
||||
### 1. Verify Database Connection and Migrations
|
||||
|
||||
#### Option A: Using Application Logs
|
||||
|
||||
When you start the application, you should see:
|
||||
- Database connection successful
|
||||
- Migrations executed (tables created)
|
||||
|
||||
#### Option B: Using PostgreSQL Client
|
||||
|
||||
```bash
|
||||
# Connect to database
|
||||
docker exec -it goplt-postgres psql -U goplt -d goplt
|
||||
|
||||
# List tables (should see User, Role, Permission, AuditLog, etc.)
|
||||
\dt
|
||||
|
||||
# Check a specific table structure
|
||||
\d users
|
||||
\d roles
|
||||
\d permissions
|
||||
\d audit_logs
|
||||
|
||||
# Exit psql
|
||||
\q
|
||||
```
|
||||
|
||||
#### Option C: Using SQL Query
|
||||
|
||||
```bash
|
||||
# Execute SQL query
|
||||
docker exec -it goplt-postgres psql -U goplt -d goplt -c "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public';"
|
||||
|
||||
# Expected output should include:
|
||||
# - users
|
||||
# - roles
|
||||
# - permissions
|
||||
# - audit_logs
|
||||
# - user_roles
|
||||
# - role_permissions
|
||||
```
|
||||
|
||||
### 2. Verify Health Endpoints
|
||||
|
||||
```bash
|
||||
# Test liveness probe (should return 200)
|
||||
curl http://localhost:8080/healthz
|
||||
|
||||
# Expected response:
|
||||
# {"status":"healthy"}
|
||||
|
||||
# Test readiness probe (should return 200 if database is connected)
|
||||
curl http://localhost:8080/ready
|
||||
|
||||
# Expected response:
|
||||
# {"status":"healthy","components":[{"name":"database","status":"healthy"}]}
|
||||
|
||||
# If database is not connected, you'll see:
|
||||
# {"status":"unhealthy","components":[{"name":"database","status":"unhealthy","error":"..."}]}
|
||||
```
|
||||
|
||||
### 3. Verify Metrics Endpoint
|
||||
|
||||
```bash
|
||||
# Get Prometheus metrics
|
||||
curl http://localhost:8080/metrics
|
||||
|
||||
# Expected output should include:
|
||||
# - http_request_duration_seconds
|
||||
# - http_requests_total
|
||||
# - http_errors_total
|
||||
# - go_* (Go runtime metrics)
|
||||
# - process_* (Process metrics)
|
||||
```
|
||||
|
||||
### 4. Verify HTTP Server Functionality
|
||||
|
||||
```bash
|
||||
# Make a request to trigger logging and metrics
|
||||
curl -v http://localhost:8080/healthz
|
||||
|
||||
# Check application logs for:
|
||||
# - Request ID in logs
|
||||
# - Structured JSON logs
|
||||
# - Request method, path, status, duration
|
||||
```
|
||||
|
||||
### 5. Verify Error Handling
|
||||
|
||||
To test panic recovery and error bus:
|
||||
|
||||
```bash
|
||||
# The error bus will capture any panics automatically
|
||||
# Check logs for error bus messages when errors occur
|
||||
```
|
||||
|
||||
### 6. Verify OpenTelemetry Tracing
|
||||
|
||||
#### Development Mode (stdout)
|
||||
|
||||
When `tracing.enabled: true` and `environment: development`, traces are exported to stdout:
|
||||
|
||||
```bash
|
||||
# Start the application and make requests
|
||||
curl http://localhost:8080/healthz
|
||||
|
||||
# Check application stdout for trace output
|
||||
# Should see JSON trace spans with:
|
||||
# - Trace ID
|
||||
# - Span ID
|
||||
# - Operation name
|
||||
# - Attributes (method, path, status, etc.)
|
||||
```
|
||||
|
||||
#### Verify Trace ID in Logs
|
||||
|
||||
```bash
|
||||
# Make a request
|
||||
curl http://localhost:8080/healthz
|
||||
|
||||
# Check application logs for trace_id and span_id fields
|
||||
# Example log entry:
|
||||
# {"level":"info","msg":"HTTP request","method":"GET","path":"/healthz","status":200,"trace_id":"...","span_id":"..."}
|
||||
```
|
||||
|
||||
### 7. Verify Database Operations
|
||||
|
||||
#### Test Database Write
|
||||
|
||||
You can test database operations by creating a simple test script or using the database client directly. For now, verify that migrations worked (see Verification 1).
|
||||
|
||||
#### Test Database Health Check
|
||||
|
||||
```bash
|
||||
# The /ready endpoint includes database health check
|
||||
curl http://localhost:8080/ready
|
||||
|
||||
# If healthy, you'll see database component status: "healthy"
|
||||
```
|
||||
|
||||
## Testing Database Specifically
|
||||
|
||||
### Direct Database Testing
|
||||
|
||||
1. **Connect to Database**:
|
||||
```bash
|
||||
docker exec -it goplt-postgres psql -U goplt -d goplt
|
||||
```
|
||||
|
||||
2. **Verify Tables Exist**:
|
||||
```sql
|
||||
SELECT table_name
|
||||
FROM information_schema.tables
|
||||
WHERE table_schema = 'public'
|
||||
ORDER BY table_name;
|
||||
```
|
||||
|
||||
3. **Check Table Structures**:
|
||||
```sql
|
||||
-- Check users table
|
||||
\d users
|
||||
|
||||
-- Check relationships
|
||||
\d user_roles
|
||||
\d role_permissions
|
||||
```
|
||||
|
||||
4. **Test Insert Operation** (manual test):
|
||||
```sql
|
||||
-- Note: Ent generates UUIDs, so we'd need to use the Ent client
|
||||
-- This is just to verify the schema is correct
|
||||
-- Actual inserts should be done through the application/Ent client
|
||||
```
|
||||
|
||||
### Using Application to Test Database
|
||||
|
||||
The database is automatically tested through:
|
||||
1. **Migrations**: Run on startup - if they succeed, schema is correct
|
||||
2. **Health Check**: `/ready` endpoint tests database connectivity
|
||||
3. **Connection Pool**: Database client manages connections automatically
|
||||
|
||||
## Docker Compose Commands
|
||||
|
||||
```bash
|
||||
# Start database
|
||||
docker-compose up -d postgres
|
||||
|
||||
# Stop database
|
||||
docker-compose stop postgres
|
||||
|
||||
# Stop and remove containers
|
||||
docker-compose down
|
||||
|
||||
# Stop and remove containers + volumes (WARNING: deletes data)
|
||||
docker-compose down -v
|
||||
|
||||
# View database logs
|
||||
docker-compose logs -f postgres
|
||||
|
||||
# Access database shell
|
||||
docker exec -it goplt-postgres psql -U goplt -d goplt
|
||||
|
||||
# Check database health
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
## Common Issues and Solutions
|
||||
|
||||
### Issue: Database connection fails
|
||||
|
||||
**Symptoms**: Application fails to start, error about database connection
|
||||
|
||||
**Solutions**:
|
||||
1. Ensure PostgreSQL container is running: `docker-compose ps`
|
||||
2. Check database DSN in config: `postgres://goplt:goplt_password@localhost:5432/goplt?sslmode=disable`
|
||||
3. Verify port 5432 is not in use: `lsof -i :5432`
|
||||
4. Check database logs: `docker-compose logs postgres`
|
||||
|
||||
### Issue: Migrations fail
|
||||
|
||||
**Symptoms**: Error during startup about migrations
|
||||
|
||||
**Solutions**:
|
||||
1. Ensure database is accessible
|
||||
2. Check database user has proper permissions
|
||||
3. Verify Ent schema is correct: `go generate ./internal/ent`
|
||||
4. Check for existing tables that might conflict
|
||||
|
||||
### Issue: Health check fails
|
||||
|
||||
**Symptoms**: `/ready` endpoint returns unhealthy
|
||||
|
||||
**Solutions**:
|
||||
1. Verify database connection
|
||||
2. Check database health: `docker-compose ps`
|
||||
3. Review application logs for specific error
|
||||
|
||||
### Issue: Metrics not appearing
|
||||
|
||||
**Symptoms**: `/metrics` endpoint is empty or missing metrics
|
||||
|
||||
**Solutions**:
|
||||
1. Make some HTTP requests first (metrics are collected per request)
|
||||
2. Verify Prometheus registry is initialized
|
||||
3. Check middleware is registered correctly
|
||||
|
||||
### Issue: Traces not appearing
|
||||
|
||||
**Symptoms**: No trace output in logs
|
||||
|
||||
**Solutions**:
|
||||
1. Verify `tracing.enabled: true` in config
|
||||
2. Check environment is set correctly (development = stdout, production = OTLP)
|
||||
3. Make HTTP requests to generate traces
|
||||
|
||||
## Expected Application Output
|
||||
|
||||
When running successfully, you should see logs like:
|
||||
|
||||
```json
|
||||
{"level":"info","msg":"Application starting","component":"bootstrap"}
|
||||
{"level":"info","msg":"Database migrations completed"}
|
||||
{"level":"info","msg":"HTTP server listening","addr":"0.0.0.0:8080"}
|
||||
```
|
||||
|
||||
When making requests:
|
||||
```json
|
||||
{"level":"info","msg":"HTTP request","method":"GET","path":"/healthz","status":200,"duration_ms":5,"request_id":"...","trace_id":"...","span_id":"..."}
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
After verifying Epic 1:
|
||||
1. All core infrastructure is in place
|
||||
2. Database is ready for Epic 2 (Authentication & Authorization)
|
||||
3. HTTP server is ready for API endpoints
|
||||
4. Observability is ready for production monitoring
|
||||
|
||||
Proceed to [Epic 2](../epic2/README.md) to implement authentication and authorization features.
|
||||
|
||||
44
go.mod
44
go.mod
@@ -4,11 +4,17 @@ go 1.24
|
||||
|
||||
require (
|
||||
entgo.io/ent v0.14.5
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/gin-gonic/gin v1.10.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/lib/pq v1.10.9
|
||||
github.com/prometheus/client_golang v1.23.2
|
||||
github.com/spf13/viper v1.18.0
|
||||
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.63.0
|
||||
go.opentelemetry.io/otel v1.38.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0
|
||||
go.opentelemetry.io/otel/sdk v1.38.0
|
||||
go.opentelemetry.io/otel/trace v1.38.0
|
||||
go.uber.org/fx v1.24.0
|
||||
go.uber.org/zap v1.26.0
|
||||
)
|
||||
@@ -19,31 +25,36 @@ require (
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bmatcuk/doublestar v1.3.4 // indirect
|
||||
github.com/bytedance/sonic v1.9.1 // indirect
|
||||
github.com/bytedance/sonic v1.14.0 // indirect
|
||||
github.com/bytedance/sonic/loader v0.3.0 // indirect
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/inflect v0.19.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.14.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/go-playground/validator/v10 v10.27.0 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.18.1 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.66.1 // indirect
|
||||
github.com/prometheus/procfs v0.16.1 // indirect
|
||||
@@ -55,19 +66,26 @@ require (
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.11 // indirect
|
||||
github.com/ugorji/go/codec v1.3.0 // indirect
|
||||
github.com/zclconf/go-cty v1.14.4 // indirect
|
||||
github.com/zclconf/go-cty-yaml v1.1.0 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.7.1 // indirect
|
||||
go.uber.org/dig v1.19.0 // indirect
|
||||
go.uber.org/multierr v1.10.0 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/arch v0.3.0 // indirect
|
||||
golang.org/x/arch v0.20.0 // indirect
|
||||
golang.org/x/crypto v0.41.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||
golang.org/x/mod v0.26.0 // indirect
|
||||
golang.org/x/net v0.43.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
|
||||
google.golang.org/grpc v1.75.0 // indirect
|
||||
google.golang.org/protobuf v1.36.8 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
110
go.sum
110
go.sum
@@ -12,14 +12,16 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bmatcuk/doublestar v1.3.4 h1:gPypJ5xD31uhX6Tf54sDPUOBXTqKH4c9aPY66CyQrS0=
|
||||
github.com/bmatcuk/doublestar v1.3.4/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
|
||||
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/bytedance/sonic v1.14.0 h1:/OfKt8HFw0kh2rj8N0F6C/qPGRESq0BbaNZgcNXXzQQ=
|
||||
github.com/bytedance/sonic v1.14.0/go.mod h1:WoEbx8WTcFJfzCe0hbmyTGrfjt8PzNEBdxlNUO24NhA=
|
||||
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
|
||||
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
@@ -28,12 +30,17 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||
github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ=
|
||||
github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4=
|
||||
github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
@@ -42,17 +49,21 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
|
||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
|
||||
github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
|
||||
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hashicorp/hcl/v2 v2.18.1 h1:6nxnOJFku1EuSawSD81fuviYUV8DxFr3fp2dUi3ZYSo=
|
||||
@@ -61,23 +72,22 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
|
||||
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
|
||||
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
||||
@@ -91,8 +101,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
@@ -104,8 +114,8 @@ github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9Z
|
||||
github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA=
|
||||
github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
|
||||
github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
@@ -126,24 +136,45 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
|
||||
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
||||
github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
|
||||
github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
|
||||
github.com/zclconf/go-cty-yaml v1.1.0 h1:nP+jp0qPHv2IhUVqmQSzjvqAWcObN0KBkUl2rWBdig0=
|
||||
github.com/zclconf/go-cty-yaml v1.1.0/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.63.0 h1:5kSIJ0y8ckZZKoDhZHdVtcyjVi6rXyAwyaR8mp4zLbg=
|
||||
go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.63.0/go.mod h1:i+fIMHvcSQtsIY82/xgiVWRklrNt/O6QriHLjzGeY+s=
|
||||
go.opentelemetry.io/contrib/propagators/b3 v1.38.0 h1:uHsCCOSKl0kLrV2dLkFK+8Ywk9iKa/fptkytc6aFFEo=
|
||||
go.opentelemetry.io/contrib/propagators/b3 v1.38.0/go.mod h1:wMRSZJZcY8ya9mApLLhwIMjqmApy2o/Ml+62lhvxyHU=
|
||||
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
|
||||
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE=
|
||||
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE=
|
||||
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
|
||||
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
|
||||
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
|
||||
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
|
||||
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
|
||||
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
|
||||
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
|
||||
go.uber.org/dig v1.19.0 h1:BACLhebsYdpQ7IROQ1AGPjrXcP5dF80U3gKoFzbaq/4=
|
||||
go.uber.org/dig v1.19.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
|
||||
go.uber.org/fx v1.24.0 h1:wE8mruvpg2kiiL1Vqd0CC+tr0/24XIB10Iwp2lLWzkg=
|
||||
@@ -156,9 +187,8 @@ go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
|
||||
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
||||
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
|
||||
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
|
||||
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.20.0 h1:dx1zTU0MAE98U+TQ8BLl7XsJbgze2WnNKF/8tGp/Q6c=
|
||||
golang.org/x/arch v0.20.0/go.mod h1:bdwinDaKcfZUGpH09BB7ZmOfhalA8lQdzl62l8gGWsk=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||
@@ -167,12 +197,19 @@ golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
|
||||
golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 h1:BIRfGDEjiHRrk0QKZe3Xv2ieMhtgRGeLcZQ0mIVn4EY=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5/go.mod h1:j3QtIyytwqGr1JUDtYXwtMXWPKsEa5LtzIFN1Wn5WvE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 h1:eaY8u2EuxbRv7c3NiGK0/NedzVsCcV6hDuU5qPX5EGE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5/go.mod h1:M4/wBTSeyLxupu3W3tJtOgB14jILAS/XWPSSa3TAlJc=
|
||||
google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4=
|
||||
google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ=
|
||||
google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc=
|
||||
google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -183,4 +220,3 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
||||
@@ -13,10 +13,12 @@ import (
|
||||
"git.dcentral.systems/toolz/goplt/internal/infra/database"
|
||||
loggerimpl "git.dcentral.systems/toolz/goplt/internal/logger"
|
||||
"git.dcentral.systems/toolz/goplt/internal/metrics"
|
||||
"git.dcentral.systems/toolz/goplt/internal/observability"
|
||||
"git.dcentral.systems/toolz/goplt/internal/server"
|
||||
"git.dcentral.systems/toolz/goplt/pkg/config"
|
||||
"git.dcentral.systems/toolz/goplt/pkg/errorbus"
|
||||
"git.dcentral.systems/toolz/goplt/pkg/logger"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.uber.org/fx"
|
||||
)
|
||||
|
||||
@@ -156,6 +158,54 @@ func ProvideMetrics() fx.Option {
|
||||
})
|
||||
}
|
||||
|
||||
// ProvideTracer creates an FX option that provides the OpenTelemetry tracer.
|
||||
func ProvideTracer() fx.Option {
|
||||
return fx.Provide(func(cfg config.ConfigProvider, lc fx.Lifecycle) (trace.TracerProvider, error) {
|
||||
enabled := cfg.GetBool("tracing.enabled")
|
||||
if !enabled {
|
||||
// Return no-op tracer
|
||||
return trace.NewNoopTracerProvider(), nil
|
||||
}
|
||||
|
||||
serviceName := cfg.GetString("tracing.service_name")
|
||||
if serviceName == "" {
|
||||
serviceName = "platform"
|
||||
}
|
||||
|
||||
serviceVersion := cfg.GetString("tracing.service_version")
|
||||
if serviceVersion == "" {
|
||||
serviceVersion = "1.0.0"
|
||||
}
|
||||
|
||||
env := cfg.GetString("environment")
|
||||
if env == "" {
|
||||
env = "development"
|
||||
}
|
||||
|
||||
otlpEndpoint := cfg.GetString("tracing.otlp_endpoint")
|
||||
|
||||
tp, err := observability.InitTracer(context.Background(), observability.Config{
|
||||
Enabled: enabled,
|
||||
ServiceName: serviceName,
|
||||
ServiceVersion: serviceVersion,
|
||||
Environment: env,
|
||||
OTLPEndpoint: otlpEndpoint,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to initialize tracer: %w", err)
|
||||
}
|
||||
|
||||
// Register lifecycle hook to shutdown tracer
|
||||
lc.Append(fx.Hook{
|
||||
OnStop: func(ctx context.Context) error {
|
||||
return observability.ShutdownTracer(ctx, tp)
|
||||
},
|
||||
})
|
||||
|
||||
return tp, nil
|
||||
})
|
||||
}
|
||||
|
||||
// ProvideHTTPServer creates an FX option that provides the HTTP server.
|
||||
func ProvideHTTPServer() fx.Option {
|
||||
return fx.Provide(func(
|
||||
@@ -164,9 +214,10 @@ func ProvideHTTPServer() fx.Option {
|
||||
healthRegistry *health.Registry,
|
||||
metricsRegistry *metrics.Metrics,
|
||||
errorBus errorbus.ErrorPublisher,
|
||||
tracer trace.TracerProvider,
|
||||
lc fx.Lifecycle,
|
||||
) (*server.Server, error) {
|
||||
srv, err := server.NewServer(cfg, log, healthRegistry, metricsRegistry, errorBus)
|
||||
srv, err := server.NewServer(cfg, log, healthRegistry, metricsRegistry, errorBus, tracer)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create HTTP server: %w", err)
|
||||
}
|
||||
@@ -194,7 +245,7 @@ func ProvideHTTPServer() fx.Option {
|
||||
}
|
||||
|
||||
// CoreModule returns an FX option that provides all core services.
|
||||
// This includes configuration, logging, database, error bus, health checks, metrics, and HTTP server.
|
||||
// This includes configuration, logging, database, error bus, health checks, metrics, tracing, and HTTP server.
|
||||
func CoreModule() fx.Option {
|
||||
return fx.Options(
|
||||
ProvideConfig(),
|
||||
@@ -203,6 +254,7 @@ func CoreModule() fx.Option {
|
||||
ProvideErrorBus(),
|
||||
ProvideHealthRegistry(),
|
||||
ProvideMetrics(),
|
||||
ProvideTracer(),
|
||||
ProvideHTTPServer(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
|
||||
"git.dcentral.systems/toolz/goplt/pkg/logger"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.uber.org/zap"
|
||||
"go.uber.org/zap/zapcore"
|
||||
)
|
||||
@@ -87,6 +88,19 @@ func (zl *zapLogger) WithContext(ctx context.Context) logger.Logger {
|
||||
fields = append(fields, zap.String("user_id", userID))
|
||||
}
|
||||
|
||||
// Extract trace ID from OpenTelemetry context
|
||||
span := trace.SpanFromContext(ctx)
|
||||
if span.SpanContext().IsValid() {
|
||||
traceID := span.SpanContext().TraceID().String()
|
||||
spanID := span.SpanContext().SpanID().String()
|
||||
if traceID != "" {
|
||||
fields = append(fields, zap.String("trace_id", traceID))
|
||||
}
|
||||
if spanID != "" {
|
||||
fields = append(fields, zap.String("span_id", spanID))
|
||||
}
|
||||
}
|
||||
|
||||
if len(fields) == 0 {
|
||||
return zl
|
||||
}
|
||||
|
||||
94
internal/observability/tracer.go
Normal file
94
internal/observability/tracer.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package observability
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
|
||||
"go.opentelemetry.io/otel/exporters/stdout/stdouttrace"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// Config holds OpenTelemetry configuration.
|
||||
type Config struct {
|
||||
Enabled bool
|
||||
ServiceName string
|
||||
ServiceVersion string
|
||||
Environment string
|
||||
OTLPEndpoint string
|
||||
}
|
||||
|
||||
// InitTracer initializes OpenTelemetry tracing.
|
||||
func InitTracer(ctx context.Context, cfg Config) (trace.TracerProvider, error) {
|
||||
if !cfg.Enabled {
|
||||
// Return a no-op tracer provider
|
||||
return trace.NewNoopTracerProvider(), nil
|
||||
}
|
||||
|
||||
// Create resource with service information
|
||||
res, err := resource.New(ctx,
|
||||
resource.WithAttributes(
|
||||
semconv.ServiceNameKey.String(cfg.ServiceName),
|
||||
semconv.ServiceVersionKey.String(cfg.ServiceVersion),
|
||||
semconv.DeploymentEnvironmentKey.String(cfg.Environment),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create resource: %w", err)
|
||||
}
|
||||
|
||||
var exporter sdktrace.SpanExporter
|
||||
|
||||
if cfg.Environment == "production" && cfg.OTLPEndpoint != "" {
|
||||
// Production: export to OTLP collector
|
||||
exporter, err = otlptracehttp.New(ctx,
|
||||
otlptracehttp.WithEndpoint(cfg.OTLPEndpoint),
|
||||
otlptracehttp.WithInsecure(), // Use WithTLSClientConfig for secure connections
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create OTLP exporter: %w", err)
|
||||
}
|
||||
} else {
|
||||
// Development: export to stdout
|
||||
exporter, err = stdouttrace.New(
|
||||
stdouttrace.WithPrettyPrint(),
|
||||
stdouttrace.WithWriter(os.Stdout),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create stdout exporter: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Create tracer provider
|
||||
tp := sdktrace.NewTracerProvider(
|
||||
sdktrace.WithBatcher(exporter),
|
||||
sdktrace.WithResource(res),
|
||||
sdktrace.WithSampler(sdktrace.AlwaysSample()), // Sample all traces in dev, can be adjusted for prod
|
||||
)
|
||||
|
||||
// Set global tracer provider
|
||||
otel.SetTracerProvider(tp)
|
||||
|
||||
// Set global propagator for trace context
|
||||
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
|
||||
propagation.TraceContext{},
|
||||
propagation.Baggage{},
|
||||
))
|
||||
|
||||
return tp, nil
|
||||
}
|
||||
|
||||
// ShutdownTracer gracefully shuts down the tracer provider.
|
||||
func ShutdownTracer(ctx context.Context, tp trace.TracerProvider) error {
|
||||
if ttp, ok := tp.(*sdktrace.TracerProvider); ok {
|
||||
return ttp.Shutdown(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"git.dcentral.systems/toolz/goplt/internal/health"
|
||||
"git.dcentral.systems/toolz/goplt/internal/metrics"
|
||||
"git.dcentral.systems/toolz/goplt/pkg/config"
|
||||
@@ -27,6 +29,7 @@ func NewServer(
|
||||
healthRegistry *health.Registry,
|
||||
metricsRegistry *metrics.Metrics,
|
||||
errorBus errorbus.ErrorPublisher,
|
||||
tracer trace.TracerProvider,
|
||||
) (*Server, error) {
|
||||
// Set Gin mode
|
||||
env := cfg.GetString("environment")
|
||||
@@ -37,6 +40,10 @@ func NewServer(
|
||||
router := gin.New()
|
||||
|
||||
// Add middleware (order matters!)
|
||||
// OpenTelemetry tracing should be first to capture all requests
|
||||
if tracer != nil {
|
||||
router.Use(otelgin.Middleware("platform", otelgin.WithTracerProvider(tracer)))
|
||||
}
|
||||
router.Use(RequestIDMiddleware())
|
||||
router.Use(LoggingMiddleware(log))
|
||||
router.Use(PanicRecoveryMiddleware(errorBus))
|
||||
|
||||
Reference in New Issue
Block a user