Skip to content

Commit eb9a9d9

Browse files
committed
Add observability to OE and PDP
1 parent 4bac6d9 commit eb9a9d9

18 files changed

Lines changed: 388 additions & 29 deletions

File tree

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,7 @@ audit-service/data/
5454
# Allow .choreo directories for WSO2 Choreo deployment
5555
!**/.choreo/
5656
!**/.choreo/**
57+
58+
# Database data directories (local development)
59+
exchange/pdp-data/
60+
exchange/ce-data/

exchange/consent-engine/main.go

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

35+
// Initialize monitoring/observability (optional - can be disabled via ENABLE_OBSERVABILITY=false)
36+
// Services will continue to function normally even if observability is disabled
37+
if monitoring.IsObservabilityEnabled() {
38+
monitoringConfig := monitoring.DefaultConfig("consent-engine")
39+
if err := monitoring.Initialize(monitoringConfig); err != nil {
40+
slog.Warn("Failed to initialize monitoring (service will continue)", "error", err)
41+
}
42+
} else {
43+
slog.Info("Observability disabled via environment variable")
44+
}
45+
3546
slog.Info("Starting consent engine",
3647
"environment", cfg.Environment,
3748
"port", cfg.Service.Port,

exchange/docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,4 +98,4 @@ services:
9898
networks:
9999
opendif-network:
100100
name: opendif-network
101-
external: true
101+
external: true

exchange/minimal-config.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"ceUrl": "http://consent-engine:8081",
3+
"pdpUrl": "http://policy-decision-point:8082",
4+
"providers": [],
5+
"argMappings": []
6+
}

exchange/orchestration-engine/provider/provider.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import (
66
"fmt"
77
"net/http"
88
"sync"
9+
"time"
910

1011
"github.com/ginaxu1/gov-dx-sandbox/exchange/orchestration-engine/logger"
1112
"github.com/ginaxu1/gov-dx-sandbox/exchange/orchestration-engine/pkg/auth"
13+
"github.com/gov-dx-sandbox/exchange/shared/monitoring"
1214
"golang.org/x/oauth2/clientcredentials"
1315
)
1416

@@ -47,7 +49,7 @@ func NewProvider(serviceKey, serviceUrl, schemaID string, authConfig *auth.AuthC
4749
}
4850

4951
// PerformRequest performs the HTTP request to the provider with necessary authentication.
50-
func (p *Provider) PerformRequest(ctx context.Context, reqBody []byte) (*http.Response, error) {
52+
func (p *Provider) PerformRequest(ctx context.Context, reqBody []byte) (resp *http.Response, err error) {
5153
// 1. Create Request
5254
req, err := http.NewRequestWithContext(ctx, "POST", p.ServiceUrl, bytes.NewBuffer(reqBody))
5355
if err != nil {
@@ -56,21 +58,29 @@ func (p *Provider) PerformRequest(ctx context.Context, reqBody []byte) (*http.Re
5658

5759
req.Header.Set("Content-Type", "application/json")
5860

61+
start := time.Now()
62+
defer func() {
63+
monitoring.RecordExternalCall(p.ServiceKey, "provider_request", time.Since(start), err)
64+
}()
65+
5966
if p.Auth != nil {
6067
switch p.Auth.Type {
6168
case auth.AuthTypeOAuth2:
6269
if p.OAuth2Config == nil {
63-
logger.Log.Error("OAuth2Config is nil", "providerKey", p.ServiceKey)
64-
return nil, fmt.Errorf("OAuth2Config is nil")
70+
err = fmt.Errorf("OAuth2Config is nil")
71+
logger.Log.Error(err.Error(), "providerKey", p.ServiceKey)
72+
return
6573
}
6674

6775
client := p.OAuth2Config.Client(ctx)
68-
return client.Do(req) // Use context with request
76+
resp, err = client.Do(req)
77+
return
6978
case auth.AuthTypeAPIKey:
7079
req.Header.Set(p.Auth.APIKeyName, p.Auth.APIKeyValue)
7180
}
7281
}
7382

7483
// Default client execution (for API Key or no auth)
75-
return p.Client.Do(req)
84+
resp, err = p.Client.Do(req)
85+
return
7686
}

exchange/orchestration-engine/server/server.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"github.com/ginaxu1/gov-dx-sandbox/exchange/orchestration-engine/pkg/graphql"
1818
"github.com/ginaxu1/gov-dx-sandbox/exchange/orchestration-engine/services"
1919
"github.com/go-chi/chi/v5"
20+
"github.com/gov-dx-sandbox/exchange/shared/monitoring"
2021
)
2122

2223
type Response struct {
@@ -85,6 +86,7 @@ func RunServer(ctx context.Context, f *federator.Federator) {
8586
// SetupRouter initializes the router and registers all endpoints
8687
func SetupRouter(f *federator.Federator) *chi.Mux {
8788
mux := chi.NewRouter()
89+
mux.Use(monitoring.HTTPMetricsMiddleware)
8890

8991
// Initialize database connection
9092
dbConnectionString := getDatabaseConnectionString()
@@ -123,6 +125,9 @@ func SetupRouter(f *federator.Federator) *chi.Mux {
123125
}
124126
})
125127

128+
// Metrics endpoint
129+
mux.Method("GET", "/metrics", monitoring.Handler())
130+
126131
// Schema management routes
127132
mux.Get("/sdl", schemaHandler.GetActiveSchema)
128133
mux.Post("/sdl", schemaHandler.CreateSchema)
@@ -135,6 +140,7 @@ func SetupRouter(f *federator.Federator) *chi.Mux {
135140

136141
// Publicly accessible Endpoints
137142
mux.Post("/public/graphql", func(w http.ResponseWriter, r *http.Request) {
143+
138144
// Parse request body
139145
var req graphql.Request
140146
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
@@ -181,6 +187,12 @@ func SetupRouter(f *federator.Federator) *chi.Mux {
181187
logger.Log.Error("Failed to write response", "error", err)
182188
return
183189
}
190+
191+
outcome := "success"
192+
if len(response.Errors) > 0 {
193+
outcome = "failure"
194+
}
195+
monitoring.RecordBusinessEvent("graphql_request", outcome)
184196
})
185197

186198
return mux

exchange/policy-decision-point/go.mod

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.24.6
44

55
require (
66
github.com/google/uuid v1.6.0
7+
github.com/gov-dx-sandbox/exchange/shared/monitoring v0.0.0
78
github.com/gov-dx-sandbox/exchange/shared/utils v0.0.0
89
github.com/joho/godotenv v1.5.1
910
github.com/stretchr/testify v1.10.0
@@ -13,20 +14,44 @@ require (
1314
)
1415

1516
require (
17+
github.com/beorn7/perks v1.0.1 // indirect
18+
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
19+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
1620
github.com/davecgh/go-spew v1.1.1 // indirect
21+
github.com/go-logr/logr v1.4.2 // indirect
22+
github.com/go-logr/stdr v1.2.2 // indirect
23+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect
1724
github.com/jackc/pgpassfile v1.0.0 // indirect
1825
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
1926
github.com/jackc/pgx/v5 v5.6.0 // indirect
2027
github.com/jackc/puddle/v2 v2.2.2 // indirect
2128
github.com/jinzhu/inflection v1.0.0 // indirect
2229
github.com/jinzhu/now v1.1.5 // indirect
23-
github.com/kr/pretty v0.3.1 // indirect
30+
github.com/klauspost/compress v1.17.9 // indirect
2431
github.com/mattn/go-sqlite3 v1.14.22 // indirect
32+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
2533
github.com/pmezard/go-difflib v1.0.0 // indirect
26-
github.com/rogpeppe/go-internal v1.13.1 // indirect
34+
github.com/prometheus/client_golang v1.20.5 // indirect
35+
github.com/prometheus/client_model v0.6.1 // indirect
36+
github.com/prometheus/common v0.60.1 // indirect
37+
github.com/prometheus/procfs v0.15.1 // indirect
38+
go.opentelemetry.io/otel v1.32.0 // indirect
39+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 // indirect
40+
go.opentelemetry.io/otel/exporters/prometheus v0.54.0 // indirect
41+
go.opentelemetry.io/otel/metric v1.32.0 // indirect
42+
go.opentelemetry.io/otel/sdk v1.32.0 // indirect
43+
go.opentelemetry.io/otel/sdk/metric v1.32.0 // indirect
44+
go.opentelemetry.io/otel/trace v1.32.0 // indirect
45+
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
2746
golang.org/x/crypto v0.40.0 // indirect
47+
golang.org/x/net v0.41.0 // indirect
2848
golang.org/x/sync v0.16.0 // indirect
49+
golang.org/x/sys v0.34.0 // indirect
2950
golang.org/x/text v0.27.0 // indirect
51+
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect
52+
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect
53+
google.golang.org/grpc v1.67.1 // indirect
54+
google.golang.org/protobuf v1.35.1 // indirect
3055
gopkg.in/yaml.v3 v3.0.1 // indirect
3156
)
3257

@@ -35,3 +60,5 @@ replace github.com/gov-dx-sandbox/exchange/shared/config => ./shared/config
3560
replace github.com/gov-dx-sandbox/exchange/shared/constants => ./shared/constants
3661

3762
replace github.com/gov-dx-sandbox/exchange/shared/utils => ./shared/utils
63+
64+
replace github.com/gov-dx-sandbox/exchange/shared/monitoring => ../shared/monitoring

exchange/policy-decision-point/go.sum

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,23 @@
1-
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
1+
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
2+
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
3+
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
4+
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
5+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
6+
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
27
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
38
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
49
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
10+
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
11+
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
12+
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
13+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
14+
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
15+
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
16+
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
517
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
618
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
19+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU=
20+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0=
721
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
822
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
923
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
@@ -18,29 +32,69 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
1832
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
1933
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
2034
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
35+
github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
36+
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
2137
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
2238
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
2339
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
2440
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
41+
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
42+
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
2543
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
2644
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
27-
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
45+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
46+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
2847
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
2948
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
30-
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
49+
github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
50+
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
51+
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
52+
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
53+
github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPAaSc=
54+
github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
55+
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
56+
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
3157
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
3258
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
3359
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
3460
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
3561
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
3662
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
3763
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
64+
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
65+
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
66+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0 h1:t/Qur3vKSkUCcDVaSumWF2PKHt85pc7fRvFuoVT8qFU=
67+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.32.0/go.mod h1:Rl61tySSdcOJWoEgYZVtmnKdA0GeKrSqkHC1t+91CH8=
68+
go.opentelemetry.io/otel/exporters/prometheus v0.54.0 h1:rFwzp68QMgtzu9PgP3jm9XaMICI6TsofWWPcBDKwlsU=
69+
go.opentelemetry.io/otel/exporters/prometheus v0.54.0/go.mod h1:QyjcV9qDP6VeK5qPyKETvNjmaaEc7+gqjh4SS0ZYzDU=
70+
go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
71+
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
72+
go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4=
73+
go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
74+
go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiyYCU9snn1CU=
75+
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
76+
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
77+
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
78+
go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0=
79+
go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8=
3880
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
3981
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
82+
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
83+
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
4084
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
4185
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
86+
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
87+
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
4288
golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
4389
golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU=
90+
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 h1:M0KvPgPmDZHPlbRbaNU1APr28TvwvvdUPlSv7PUvy8g=
91+
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:dguCy7UOdZhTvLzDyt15+rOrawrpM4q7DD9dQ1P11P4=
92+
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 h1:XVhgTWWV3kGQlwJHR3upFWZeTsei6Oks1apkZSeonIE=
93+
google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI=
94+
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
95+
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
96+
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
97+
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
4498
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
4599
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
46100
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

exchange/policy-decision-point/main.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"time"
99

1010
v1 "github.com/gov-dx-sandbox/exchange/policy-decision-point/v1"
11+
"github.com/gov-dx-sandbox/exchange/shared/monitoring"
1112
"github.com/gov-dx-sandbox/exchange/shared/utils"
1213
"github.com/joho/godotenv"
1314
)
@@ -26,6 +27,17 @@ func main() {
2627
// Setup logging
2728
utils.SetupLogging("json", getEnvOrDefault("LOG_LEVEL", "info"))
2829

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")
39+
}
40+
2941
slog.Info("Starting policy decision point (V1)",
3042
"version", Version,
3143
"build_time", BuildTime,
@@ -55,6 +67,9 @@ func main() {
5567
mux := http.NewServeMux()
5668
v1Handler.SetupRoutes(mux) // V1 routes with /api/v1/policy/ prefix
5769

70+
// Metrics endpoint
71+
mux.Handle("/metrics", monitoring.Handler())
72+
5873
// Health check endpoint
5974
mux.Handle("/health", utils.PanicRecoveryMiddleware(utils.HealthHandler("policy-decision-point")))
6075

@@ -128,6 +143,9 @@ func main() {
128143
utils.RespondWithJSON(w, http.StatusOK, debugInfo)
129144
})))
130145

146+
// Wrap with metrics middleware
147+
handler := monitoring.HTTPMetricsMiddleware(mux)
148+
131149
// Create server using utils
132150
port := getEnvOrDefault("PORT", "8082")
133151
serverConfig := &utils.ServerConfig{
@@ -136,7 +154,7 @@ func main() {
136154
WriteTimeout: 15 * time.Second,
137155
IdleTimeout: 60 * time.Second,
138156
}
139-
server := utils.CreateServer(serverConfig, mux)
157+
server := utils.CreateServer(serverConfig, handler)
140158

141159
// Start server with graceful shutdown
142160
if err := utils.StartServerWithGracefulShutdown(server, "policy-decision-point"); err != nil {

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
//

0 commit comments

Comments
 (0)