Skip to content

Commit b189505

Browse files
committed
refactor: align implementations and improve error messages
- Fix Go debug default from true to false for security - Align API-first FastAPI logging with code-first (structured JSON) - Update API-first version to 1.1.0 to match code-first - Add rate limiting to API-first metrics endpoint - Add structured logging to API-first middleware - Remove outdated pytest version comment - Improve VAULT_TOKEN error message in generate-certificates.sh - Run go mod tidy to fix missing go.sum entries
1 parent 33a2818 commit b189505

6 files changed

Lines changed: 84 additions & 20 deletions

File tree

reference-apps/fastapi-api-first/app/main.py

Lines changed: 66 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
from slowapi.errors import RateLimitExceeded
1515
from prometheus_client import Counter, Histogram, Gauge, generate_latest, CONTENT_TYPE_LATEST
1616
import logging
17+
import sys
1718
import time
1819
import uuid
20+
from pythonjsonlogger import jsonlogger
1921

2022
from app.routers import (
2123
health_checks,
@@ -30,12 +32,19 @@
3032
from app.middleware.cache import cache_manager
3133
from app.services.vault import vault_client
3234

33-
# Configure logging
34-
logging.basicConfig(
35-
level=logging.INFO,
36-
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
35+
# Configure structured JSON logging (matches code-first implementation)
36+
logHandler = logging.StreamHandler(sys.stdout)
37+
formatter = jsonlogger.JsonFormatter(
38+
'%(asctime)s %(name)s %(levelname)s %(message)s %(request_id)s %(method)s %(path)s %(status_code)s %(duration_ms)s'
3739
)
40+
logHandler.setFormatter(formatter)
3841
logger = logging.getLogger(__name__)
42+
logger.addHandler(logHandler)
43+
logger.setLevel(logging.INFO)
44+
45+
# Disable default basicConfig
46+
logging.getLogger().handlers.clear()
47+
logging.getLogger().addHandler(logHandler)
3948

4049
# Prometheus metrics
4150
http_requests_total = Counter(
@@ -68,7 +77,7 @@
6877
# Create FastAPI app
6978
app = FastAPI(
7079
title="DevStack Core - Reference API (API-First)",
71-
version="1.0.0",
80+
version="1.1.0",
7281
description="API-First implementation generated from OpenAPI specification",
7382
docs_url="/docs",
7483
redoc_url="/redoc",
@@ -112,10 +121,10 @@ async def metrics_middleware(request: Request, call_next):
112121
request.state.request_id = request_id
113122

114123
method = request.method
115-
path = request.url.path
124+
endpoint = request.url.path
116125

117126
# Track in-progress requests
118-
http_requests_in_progress.labels(method=method, endpoint=path).inc()
127+
http_requests_in_progress.labels(method=method, endpoint=endpoint).inc()
119128

120129
start_time = time.time()
121130

@@ -126,23 +135,58 @@ async def metrics_middleware(request: Request, call_next):
126135
# Record metrics
127136
http_requests_total.labels(
128137
method=method,
129-
endpoint=path,
138+
endpoint=endpoint,
130139
status=response.status_code
131140
).inc()
132141

133142
http_request_duration_seconds.labels(
134143
method=method,
135-
endpoint=path
144+
endpoint=endpoint
136145
).observe(duration)
137146

147+
# Log request with structured data (matches code-first implementation)
148+
logger.info(
149+
"HTTP request completed",
150+
extra={
151+
"request_id": request_id,
152+
"method": method,
153+
"path": endpoint,
154+
"status_code": response.status_code,
155+
"duration_ms": round(duration * 1000, 2)
156+
}
157+
)
158+
138159
# Add headers
139160
response.headers["X-Request-ID"] = request_id
140161
response.headers["X-Response-Time"] = f"{duration:.3f}s"
141162

142163
return response
143164

165+
except Exception as e:
166+
# Record error metrics
167+
duration = time.time() - start_time
168+
http_requests_total.labels(
169+
method=method,
170+
endpoint=endpoint,
171+
status=500
172+
).inc()
173+
174+
# Log error with structured data
175+
logger.error(
176+
f"Request failed: {str(e)}",
177+
extra={
178+
"request_id": request_id,
179+
"method": method,
180+
"path": endpoint,
181+
"status_code": 500,
182+
"duration_ms": round(duration * 1000, 2)
183+
},
184+
exc_info=True
185+
)
186+
raise
187+
144188
finally:
145-
http_requests_in_progress.labels(method=method, endpoint=path).dec()
189+
http_requests_in_progress.labels(method=method, endpoint=endpoint).dec()
146190

147191

148192
# Include routers
@@ -158,7 +202,7 @@ async def metrics_middleware(request: Request, call_next):
158202
async def startup_event():
159203
"""Application startup event handler."""
160204
# Set app info metric
161-
app_info.labels(version="1.0.0", name="api-first").set(1)
205+
app_info.labels(version="1.1.0", name="api-first").set(1)
162206

163207
# Initialize response caching with Redis
164208
try:
@@ -171,10 +215,14 @@ async def startup_event():
171215
logger.error(f"Failed to initialize cache: {e}")
172216
logger.warning("Application will continue without caching")
173217

174-
logger.info("Starting API-First FastAPI application...")
175-
logger.info(f"Debug mode: {settings.DEBUG}")
176-
logger.info(f"Vault address: {settings.VAULT_ADDR}")
177-
logger.info(f"Redis cache enabled: {cache_manager.enabled}")
218+
logger.info(
219+
"Starting DevStack Core Reference API (API-First)",
220+
extra={
221+
"vault_address": settings.VAULT_ADDR,
222+
"redis_cache_enabled": cache_manager.enabled,
223+
"version": "1.1.0"
224+
}
225+
)
178226
logger.info("Application ready")
179227

180228

@@ -195,7 +243,7 @@ async def root(request: Request):
195243
"""
196244
return {
197245
"name": "DevStack Core Reference API",
198-
"version": "1.0.0",
246+
"version": "1.1.0",
199247
"description": "Reference implementation for infrastructure integration",
200248
"docs": "/docs",
201249
"health": "/health/all",
@@ -253,7 +301,8 @@ async def root(request: Request):
253301

254302

255303
@app.get("/metrics")
256-
async def metrics():
304+
@limiter.limit("1000/minute") # High limit for metrics scraping
305+
async def metrics(request: Request):
257306
"""Prometheus metrics endpoint"""
258307
return Response(
259308
content=generate_latest(),

reference-apps/fastapi/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ python-json-logger==4.0.0
2828
prometheus-client==0.23.1
2929

3030
# Testing
31-
pytest==9.0.1 # pytest-asyncio 1.2.0 requires pytest<9
31+
pytest==9.0.1
3232
pytest-asyncio==1.3.0
3333
pytest-cov==7.0.0
3434
pytest-mock==3.15.1

reference-apps/golang/go.mod

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ require (
88
github.com/google/uuid v1.6.0
99
github.com/hashicorp/vault/api v1.22.0
1010
github.com/jackc/pgx/v5 v5.7.6
11+
github.com/prometheus/client_golang v1.19.1
1112
github.com/rabbitmq/amqp091-go v1.10.0
1213
github.com/redis/go-redis/v9 v9.17.2
1314
github.com/sirupsen/logrus v1.9.3
@@ -16,6 +17,7 @@ require (
1617

1718
require (
1819
filippo.io/edwards25519 v1.1.0 // indirect
20+
github.com/beorn7/perks v1.0.1 // indirect
1921
github.com/bytedance/sonic v1.14.0 // indirect
2022
github.com/bytedance/sonic/loader v0.3.0 // indirect
2123
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
@@ -53,6 +55,9 @@ require (
5355
github.com/modern-go/reflect2 v1.0.2 // indirect
5456
github.com/montanaflynn/stats v0.7.1 // indirect
5557
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
58+
github.com/prometheus/client_model v0.5.0 // indirect
59+
github.com/prometheus/common v0.48.0 // indirect
60+
github.com/prometheus/procfs v0.12.0 // indirect
5661
github.com/quic-go/qpack v0.5.1 // indirect
5762
github.com/quic-go/quic-go v0.54.1 // indirect
5863
github.com/ryanuber/go-glob v1.0.0 // indirect

reference-apps/golang/go.sum

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
22
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
3+
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
4+
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
35
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
46
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
57
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
@@ -110,6 +112,14 @@ github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0
110112
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
111113
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
112114
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
115+
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
116+
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
117+
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
118+
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
119+
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
120+
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
121+
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
122+
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
113123
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
114124
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
115125
github.com/quic-go/quic-go v0.54.1 h1:4ZAWm0AhCb6+hE+l5Q1NAL0iRn/ZrMwqHRGQiFwj2eg=

reference-apps/golang/internal/config/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func Load() *Config {
5757
return &Config{
5858
// Application
5959
Environment: getEnv("ENVIRONMENT", "development"),
60-
Debug: getEnvBool("DEBUG", true),
60+
Debug: getEnvBool("DEBUG", false),
6161
HTTPPort: getEnv("HTTP_PORT", "8002"),
6262
HTTPSPort: getEnv("HTTPS_PORT", "8445"),
6363
EnableTLS: getEnvBool("GOLANG_API_ENABLE_TLS", false),

scripts/generate-certificates.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ main() {
630630

631631
# Check required environment variables
632632
if [ -z "$VAULT_TOKEN" ]; then
633-
error "VAULT_TOKEN environment variable is required"
633+
error "VAULT_TOKEN not set and ~/.config/vault/root-token not found. Run './devstack vault-init' first or export VAULT_TOKEN."
634634
fi
635635

636636
# Wait for Vault

0 commit comments

Comments
 (0)