Skip to content

Commit ce39049

Browse files
committed
Refactor: Use deferred function to eliminate code duplication in provider metrics recording
1 parent 3ce39e9 commit ce39049

12 files changed

Lines changed: 298 additions & 152 deletions

File tree

exchange/consent-engine/main.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ func main() {
4040
// Setup logging
4141
utils.SetupLogging(cfg.Logging.Format, cfg.Logging.Level)
4242

43+
// Initialize monitoring/observability (optional - can be disabled via ENABLE_OBSERVABILITY=false)
44+
// Services will continue to function normally even if observability is disabled
45+
if monitoring.IsObservabilityEnabled() {
46+
monitoringConfig := monitoring.DefaultConfig("consent-engine")
47+
if err := monitoring.Initialize(monitoringConfig); err != nil {
48+
slog.Warn("Failed to initialize monitoring (service will continue)", "error", err)
49+
}
50+
} else {
51+
slog.Info("Observability disabled via environment variable")
52+
}
53+
4354
slog.Info("Starting consent engine",
4455
"environment", cfg.Environment,
4556
"port", cfg.Service.Port,

exchange/docker-compose.yml

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ services:
77
image: postgres:16-alpine
88
container_name: pdp-db-${ENVIRONMENT:-local}
99
environment:
10-
- POSTGRES_USER=postgres
11-
- POSTGRES_PASSWORD=password
12-
- POSTGRES_DB=testdb
10+
- POSTGRES_USER=${POSTGRES_USER:-postgres}
11+
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-password}
12+
- POSTGRES_DB=${POSTGRES_DB:-testdb}
1313
ports:
1414
- "${PDP_DB_PORT:-5433}:5432"
1515
healthcheck:
@@ -20,6 +20,23 @@ services:
2020
networks:
2121
- opendif-network
2222

23+
ce-db:
24+
image: postgres:16-alpine
25+
container_name: ce-db-${ENVIRONMENT:-local}
26+
environment:
27+
- POSTGRES_USER=${POSTGRES_USER:-postgres}
28+
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-password}
29+
- POSTGRES_DB=${CE_DB_NAME:-consent_db}
30+
ports:
31+
- "${CE_DB_PORT:-5434}:5432"
32+
healthcheck:
33+
test: ["CMD-SHELL", "pg_isready -U postgres"]
34+
interval: 5s
35+
timeout: 5s
36+
retries: 5
37+
networks:
38+
- opendif-network
39+
2340
policy-decision-point:
2441
build:
2542
context: .
@@ -38,12 +55,14 @@ services:
3855
- LOG_LEVEL=${LOG_LEVEL:-info}
3956
- LOG_FORMAT=${LOG_FORMAT:-text}
4057
- SERVICE_NAME=policy-decision-point
58+
- ENABLE_OBSERVABILITY=${ENABLE_OBSERVABILITY:-true}
59+
- OTEL_METRICS_ENABLED=${OTEL_METRICS_ENABLED:-true}
4160
- OTEL_METRICS_EXPORTER=${OTEL_METRICS_EXPORTER:-prometheus}
4261
- CHOREO_OPENDIF_DATABASE_HOSTNAME=pdp-db
4362
- CHOREO_OPENDIF_DATABASE_PORT=5432
44-
- CHOREO_OPENDIF_DATABASE_USERNAME=postgres
45-
- CHOREO_OPENDIF_DATABASE_PASSWORD=password
46-
- CHOREO_OPENDIF_DATABASE_DATABASENAME=testdb
63+
- CHOREO_OPENDIF_DATABASE_USERNAME=${POSTGRES_USER:-postgres}
64+
- CHOREO_OPENDIF_DATABASE_PASSWORD=${POSTGRES_PASSWORD:-password}
65+
- CHOREO_OPENDIF_DATABASE_DATABASENAME=${POSTGRES_DB:-testdb}
4766
- DB_SSLMODE=disable
4867
- RUN_MIGRATION=true
4968
depends_on:
@@ -76,12 +95,30 @@ services:
7695
- PORT=8081
7796
- LOG_LEVEL=${LOG_LEVEL:-info}
7897
- LOG_FORMAT=${LOG_FORMAT:-text}
98+
- SERVICE_NAME=consent-engine
99+
- ENABLE_OBSERVABILITY=${ENABLE_OBSERVABILITY:-true}
100+
- OTEL_METRICS_ENABLED=${OTEL_METRICS_ENABLED:-true}
101+
- OTEL_METRICS_EXPORTER=${OTEL_METRICS_EXPORTER:-prometheus}
102+
- CHOREO_OPENDIF_DATABASE_HOSTNAME=ce-db
103+
- CHOREO_OPENDIF_DATABASE_PORT=5432
104+
- CHOREO_OPENDIF_DATABASE_USERNAME=${POSTGRES_USER:-postgres}
105+
- CHOREO_OPENDIF_DATABASE_PASSWORD=${POSTGRES_PASSWORD:-password}
106+
- CHOREO_OPENDIF_DATABASE_DATABASENAME=${CE_DB_NAME:-consent_db}
107+
- DB_SSLMODE=disable
108+
- RUN_MIGRATION=true
109+
- ASGARDEO_JWKS_URL=${ASGARDEO_JWKS_URL:-https://www.googleapis.com/oauth2/v3/certs}
110+
- ASGARDEO_ISSUER=${ASGARDEO_ISSUER:-https://accounts.google.com}
111+
- ASGARDEO_AUDIENCE=${ASGARDEO_AUDIENCE:-test-audience}
112+
- ASGARDEO_ORG_NAME=${ASGARDEO_ORG_NAME:-test-org}
113+
depends_on:
114+
ce-db:
115+
condition: service_healthy
79116
healthcheck:
80117
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8081/health"]
81118
interval: 30s
82119
timeout: 10s
83120
retries: 3
84-
start_period: 10s
121+
start_period: 30s
85122
restart: unless-stopped
86123
networks:
87124
- opendif-network
@@ -104,8 +141,16 @@ services:
104141
- LOG_LEVEL=${LOG_LEVEL:-info}
105142
- LOG_FORMAT=${LOG_FORMAT:-text}
106143
- SERVICE_NAME=orchestration-engine
144+
- ENABLE_OBSERVABILITY=${ENABLE_OBSERVABILITY:-true}
145+
- OTEL_METRICS_ENABLED=${OTEL_METRICS_ENABLED:-true}
107146
- OTEL_METRICS_EXPORTER=${OTEL_METRICS_EXPORTER:-prometheus}
108147
- CONFIG_PATH=/app/config/config.json
148+
- DB_HOST=${DB_HOST?DB_HOST is required}
149+
- DB_PORT=${DB_PORT:-5432}
150+
- DB_USER=${DB_USER:-postgres}
151+
- DB_PASSWORD=${DB_PASSWORD?DB_PASSWORD is required}
152+
- DB_NAME=${DB_NAME:-orchestration_engine}
153+
- DB_SSLMODE=${DB_SSLMODE:-disable}
109154
volumes:
110155
- ./minimal-config.json:/app/config/config.json:ro
111156
healthcheck:

exchange/orchestration-engine/main.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@ import (
1616
func main() {
1717
logger.Init()
1818

19-
// Initialize monitoring/observability
20-
// This ensures metrics are properly set up before the server starts
21-
monitoringConfig := monitoring.DefaultConfig("orchestration-engine")
22-
if err := monitoring.Initialize(monitoringConfig); err != nil {
23-
logger.Log.Warn("Failed to initialize monitoring (service will continue)", "error", err)
19+
// Initialize monitoring/observability (optional - can be disabled via ENABLE_OBSERVABILITY=false)
20+
// Services will continue to function normally even if observability is disabled
21+
if monitoring.IsObservabilityEnabled() {
22+
monitoringConfig := monitoring.DefaultConfig("orchestration-engine")
23+
if err := monitoring.Initialize(monitoringConfig); err != nil {
24+
logger.Log.Warn("Failed to initialize monitoring (service will continue)", "error", err)
25+
}
26+
} else {
27+
logger.Log.Info("Observability disabled via environment variable")
2428
}
2529

2630
// Load configuration with proper error handling

exchange/orchestration-engine/provider/provider.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,27 +59,28 @@ func (p *Provider) PerformRequest(ctx context.Context, reqBody []byte) (resp *ht
5959
req.Header.Set("Content-Type", "application/json")
6060

6161
start := time.Now()
62+
defer func() {
63+
monitoring.RecordExternalCall(p.ServiceKey, "provider_request", time.Since(start), err)
64+
}()
6265

6366
if p.Auth != nil {
6467
switch p.Auth.Type {
6568
case auth.AuthTypeOAuth2:
6669
if p.OAuth2Config == nil {
6770
err = fmt.Errorf("OAuth2Config is nil")
6871
logger.Log.Error(err.Error(), "providerKey", p.ServiceKey)
69-
return nil, err
72+
return
7073
}
7174

7275
client := p.OAuth2Config.Client(ctx)
7376
resp, err = client.Do(req)
74-
monitoring.RecordExternalCall(p.ServiceKey, "provider_request", time.Since(start), err)
75-
return resp, err
77+
return
7678
case auth.AuthTypeAPIKey:
7779
req.Header.Set(p.Auth.APIKeyName, p.Auth.APIKeyValue)
7880
}
7981
}
8082

8183
// Default client execution (for API Key or no auth)
8284
resp, err = p.Client.Do(req)
83-
monitoring.RecordExternalCall(p.ServiceKey, "provider_request", time.Since(start), err)
84-
return resp, err
85+
return
8586
}

exchange/policy-decision-point/main.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,15 @@ func main() {
2727
// Setup logging
2828
utils.SetupLogging("json", getEnvOrDefault("LOG_LEVEL", "info"))
2929

30-
// Initialize monitoring/observability
31-
monitoringConfig := monitoring.DefaultConfig("policy-decision-point")
32-
if err := monitoring.Initialize(monitoringConfig); err != nil {
33-
slog.Error("Failed to initialize monitoring", "error", err)
34-
// Don't exit - service can continue without metrics
30+
// Initialize monitoring/observability (optional - can be disabled via ENABLE_OBSERVABILITY=false)
31+
// Services will continue to function normally even if observability is disabled
32+
if monitoring.IsObservabilityEnabled() {
33+
monitoringConfig := monitoring.DefaultConfig("policy-decision-point")
34+
if err := monitoring.Initialize(monitoringConfig); err != nil {
35+
slog.Warn("Failed to initialize monitoring (service will continue)", "error", err)
36+
}
37+
} else {
38+
slog.Info("Observability disabled via environment variable")
3539
}
3640

3741
slog.Info("Starting policy decision point (V1)",

exchange/shared/monitoring/metrics.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,22 @@ var (
2626

2727
// ensureInitialized ensures OpenTelemetry is initialized with default config
2828
// This is called automatically when metrics functions are used
29+
// Observability can be disabled via ENABLE_OBSERVABILITY=false or OTEL_METRICS_ENABLED=false
2930
func ensureInitialized() {
3031
initOnce.Do(func() {
32+
// Check if observability is explicitly disabled
33+
enableObservability := getEnvBoolOrDefault("ENABLE_OBSERVABILITY", true)
34+
otelMetricsEnabled := getEnvBoolOrDefault("OTEL_METRICS_ENABLED", true)
35+
36+
if !enableObservability || !otelMetricsEnabled {
37+
slog.Info("Observability disabled via environment variable, skipping initialization",
38+
"ENABLE_OBSERVABILITY", enableObservability,
39+
"OTEL_METRICS_ENABLED", otelMetricsEnabled)
40+
// Set initErr to nil so IsInitialized() returns false but no error is reported
41+
initErr = nil
42+
return
43+
}
44+
3145
// Try to get service name from environment or use default
3246
serviceName := os.Getenv("SERVICE_NAME")
3347
if serviceName == "" {
@@ -61,6 +75,15 @@ func IsInitialized() bool {
6175
return initErr == nil
6276
}
6377

78+
// IsObservabilityEnabled checks if observability is enabled via environment variables
79+
// Returns false if ENABLE_OBSERVABILITY=false or OTEL_METRICS_ENABLED=false
80+
// Returns true otherwise (default behavior)
81+
func IsObservabilityEnabled() bool {
82+
enableObservability := getEnvBoolOrDefault("ENABLE_OBSERVABILITY", true)
83+
otelMetricsEnabled := getEnvBoolOrDefault("OTEL_METRICS_ENABLED", true)
84+
return enableObservability && otelMetricsEnabled
85+
}
86+
6487
// RegisterRoutes registers routes for normalization. Supports static routes and templates with :id or {id} placeholders.
6588
// Templates match incoming paths and normalize dynamic segments. Call during service initialization.
6689
//

exchange/shared/monitoring/metrics_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"net/http"
66
"net/http/httptest"
7+
"os"
78
"strings"
89
"testing"
910
"time"
@@ -427,6 +428,85 @@ func TestMultipleInitializations(t *testing.T) {
427428
}
428429
}
429430

431+
// TestIsObservabilityEnabled tests the IsObservabilityEnabled function
432+
func TestIsObservabilityEnabled(t *testing.T) {
433+
tests := []struct {
434+
name string
435+
enableObservability string
436+
otelMetricsEnabled string
437+
expected bool
438+
}{
439+
{
440+
name: "Both enabled (default)",
441+
enableObservability: "",
442+
otelMetricsEnabled: "",
443+
expected: true,
444+
},
445+
{
446+
name: "ENABLE_OBSERVABILITY=false disables",
447+
enableObservability: "false",
448+
otelMetricsEnabled: "",
449+
expected: false,
450+
},
451+
{
452+
name: "OTEL_METRICS_ENABLED=false disables",
453+
enableObservability: "",
454+
otelMetricsEnabled: "false",
455+
expected: false,
456+
},
457+
{
458+
name: "Both false disables",
459+
enableObservability: "false",
460+
otelMetricsEnabled: "false",
461+
expected: false,
462+
},
463+
{
464+
name: "Both true enables",
465+
enableObservability: "true",
466+
otelMetricsEnabled: "true",
467+
expected: true,
468+
},
469+
}
470+
471+
for _, tt := range tests {
472+
t.Run(tt.name, func(t *testing.T) {
473+
// Save original values
474+
origEnable := os.Getenv("ENABLE_OBSERVABILITY")
475+
origOtel := os.Getenv("OTEL_METRICS_ENABLED")
476+
477+
// Set test values
478+
if tt.enableObservability != "" {
479+
os.Setenv("ENABLE_OBSERVABILITY", tt.enableObservability)
480+
} else {
481+
os.Unsetenv("ENABLE_OBSERVABILITY")
482+
}
483+
if tt.otelMetricsEnabled != "" {
484+
os.Setenv("OTEL_METRICS_ENABLED", tt.otelMetricsEnabled)
485+
} else {
486+
os.Unsetenv("OTEL_METRICS_ENABLED")
487+
}
488+
489+
// Test (function doesn't depend on initOnce, so no reset needed)
490+
result := IsObservabilityEnabled()
491+
if result != tt.expected {
492+
t.Errorf("IsObservabilityEnabled() = %v, want %v", result, tt.expected)
493+
}
494+
495+
// Restore original values
496+
if origEnable != "" {
497+
os.Setenv("ENABLE_OBSERVABILITY", origEnable)
498+
} else {
499+
os.Unsetenv("ENABLE_OBSERVABILITY")
500+
}
501+
if origOtel != "" {
502+
os.Setenv("OTEL_METRICS_ENABLED", origOtel)
503+
} else {
504+
os.Unsetenv("OTEL_METRICS_ENABLED")
505+
}
506+
})
507+
}
508+
}
509+
430510
// TestHTTPMetricsMiddlewareWithDifferentStatusCodes tests that different HTTP status codes are recorded
431511
func TestHTTPMetricsMiddlewareWithDifferentStatusCodes(t *testing.T) {
432512
testCases := []struct {

exchange/shared/monitoring/otel_metrics.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,28 @@ type Config struct {
8787
}
8888

8989
// DefaultConfig returns a default configuration
90+
// Observability can be disabled by setting ENABLE_OBSERVABILITY=false or OTEL_METRICS_ENABLED=false
9091
func DefaultConfig(serviceName string) Config {
92+
// Check if observability is explicitly disabled
93+
enableObservability := getEnvBoolOrDefault("ENABLE_OBSERVABILITY", true)
94+
otelMetricsEnabled := getEnvBoolOrDefault("OTEL_METRICS_ENABLED", true)
95+
96+
// If either flag is false, disable observability
97+
observabilityEnabled := enableObservability && otelMetricsEnabled
98+
99+
var exporterType string
100+
if !observabilityEnabled {
101+
exporterType = "none"
102+
slog.Info("Observability disabled via environment variable",
103+
"service", serviceName,
104+
"ENABLE_OBSERVABILITY", enableObservability,
105+
"OTEL_METRICS_ENABLED", otelMetricsEnabled)
106+
} else {
107+
exporterType = getEnvOrDefault("OTEL_METRICS_EXPORTER", "prometheus")
108+
}
109+
91110
return Config{
92-
ExporterType: getEnvOrDefault("OTEL_METRICS_EXPORTER", "prometheus"),
111+
ExporterType: exporterType,
93112
ServiceName: serviceName,
94113
ServiceVersion: getEnvOrDefault("SERVICE_VERSION", "dev"),
95114
OTLPEndpoint: getEnvOrDefault("OTEL_EXPORTER_OTLP_ENDPOINT", ""),

observability/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ Run the verification script to start everything and verify metrics are working:
8585

8686
```bash
8787
cd observability
88-
./verification_steps.sh
88+
./verify_observability_setup.sh
8989
```
9090

9191
This script will:

0 commit comments

Comments
 (0)