Skip to content

Commit d430a07

Browse files
authored
Merge pull request #5 from smartcontractkit/opentel
Add enclave host execution telemetry
2 parents a46e0e4 + 172096a commit d430a07

10 files changed

Lines changed: 1385 additions & 271 deletions

File tree

enclave/nitro/host/go.mod

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,46 @@ go 1.26.4
44

55
require (
66
github.com/smartcontractkit/chainlink-common v0.11.2-0.20260714160921-4033d0253977
7-
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260622152157-c8e129347b8b
87
github.com/smartcontractkit/chainlink-confidential-compute v0.0.0
8+
github.com/smartcontractkit/chainlink-protos/cre/go v0.0.0-20260622152157-c8e129347b8b
99
github.com/stretchr/testify v1.11.1
10+
go.opentelemetry.io/otel v1.43.0
11+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0
12+
go.opentelemetry.io/otel/metric v1.43.0
13+
go.opentelemetry.io/otel/sdk v1.43.0
14+
go.opentelemetry.io/otel/sdk/metric v1.43.0
1015
go.uber.org/zap v1.27.1
1116
google.golang.org/protobuf v1.36.11
1217
)
1318

1419
require (
20+
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
1521
github.com/cespare/xxhash/v2 v2.3.0 // indirect
1622
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
1723
github.com/doyensec/safeurl v0.2.2 // indirect
24+
github.com/go-logr/logr v1.4.3 // indirect
25+
github.com/go-logr/stdr v1.2.2 // indirect
26+
github.com/google/uuid v1.6.0 // indirect
27+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect
1828
github.com/mdlayher/socket v0.4.1 // indirect
1929
github.com/mdlayher/vsock v1.2.1 // indirect
2030
github.com/mr-tron/base58 v1.2.0 // indirect
2131
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
2232
github.com/shopspring/decimal v1.4.0 // indirect
2333
github.com/smartcontractkit/libocr v0.0.0-20250912173940-f3ab0246e23d // indirect
2434
github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009175230-e6634ab1b071 // indirect
25-
go.opentelemetry.io/otel v1.43.0 // indirect
35+
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
2636
go.opentelemetry.io/otel/trace v1.43.0 // indirect
37+
go.opentelemetry.io/proto/otlp v1.10.0 // indirect
2738
go.uber.org/multierr v1.11.0 // indirect
2839
golang.org/x/crypto v0.52.0 // indirect
2940
golang.org/x/net v0.55.0 // indirect
3041
golang.org/x/sync v0.20.0 // indirect
3142
golang.org/x/sys v0.45.0 // indirect
43+
golang.org/x/text v0.37.0 // indirect
44+
google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 // indirect
45+
google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 // indirect
46+
google.golang.org/grpc v1.82.1 // indirect
3247
gopkg.in/yaml.v3 v3.0.1 // indirect
3348
)
3449

enclave/nitro/host/go.sum

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
1+
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
2+
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
13
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
24
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
35
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
46
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
57
github.com/doyensec/safeurl v0.2.2 h1:+sFUqwOnqqmtUAC85/sGdOKfJh8zOacyghkaLzsOk40=
68
github.com/doyensec/safeurl v0.2.2/go.mod h1:3H0cgRpPYPSpgxRRn5yGD35Ns/LgGX/BVWSBbzUqXtY=
9+
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
10+
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
11+
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
12+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
13+
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
14+
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
15+
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
716
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
817
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
18+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
19+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
20+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs=
21+
github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c=
922
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
1023
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
1124
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -32,10 +45,22 @@ github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009175230-e6634ab1b071 h1:6
3245
github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009175230-e6634ab1b071/go.mod h1:NSc7hgOQbXG3DAwkOdWnZzLTZENXSwDJ7Va1nBp0YU0=
3346
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
3447
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
48+
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
49+
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
3550
go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I=
3651
go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0=
52+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0 h1:8UQVDcZxOJLtX6gxtDt3vY2WTgvZqMQRzjsqiIHQdkc=
53+
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.43.0/go.mod h1:2lmweYCiHYpEjQ/lSJBYhj9jP1zvCvQW4BqL9dnT7FQ=
54+
go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
55+
go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY=
56+
go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg=
57+
go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg=
58+
go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw=
59+
go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A=
3760
go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A=
3861
go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0=
62+
go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g=
63+
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
3964
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
4065
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
4166
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -50,6 +75,16 @@ golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
5075
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
5176
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
5277
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
78+
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
79+
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
80+
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
81+
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
82+
google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478 h1:yQugLulqltosq0B/f8l4w9VryjV+N/5gcW0jQ3N8Qec=
83+
google.golang.org/genproto/googleapis/api v0.0.0-20260414002931-afd174a4e478/go.mod h1:C6ADNqOxbgdUUeRTU+LCHDPB9ttAMCTff6auwCVa4uc=
84+
google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478 h1:RmoJA1ujG+/lRGNfUnOMfhCy5EipVMyvUE+KNbPbTlw=
85+
google.golang.org/genproto/googleapis/rpc v0.0.0-20260414002931-afd174a4e478/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
86+
google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE=
87+
google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA=
5388
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
5489
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
5590
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

enclave/nitro/host/host.go

Lines changed: 38 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,12 @@ import (
2121
"syscall"
2222
"time"
2323

24-
confworkflowtypes "github.com/smartcontractkit/chainlink-common/pkg/capabilities/v2/actions/confidentialworkflow"
2524
cllogger "github.com/smartcontractkit/chainlink-common/pkg/logger"
26-
sdkpb "github.com/smartcontractkit/chainlink-protos/cre/go/sdk"
27-
confhttptypes "github.com/smartcontractkit/chainlink-confidential-compute/enclave/apps/confidential-http/types"
2825
signatureverifier "github.com/smartcontractkit/chainlink-confidential-compute/enclave/services/signature-verifier"
2926
"github.com/smartcontractkit/chainlink-confidential-compute/enclave/vsock"
3027
"github.com/smartcontractkit/chainlink-confidential-compute/types"
3128
"github.com/smartcontractkit/chainlink-confidential-compute/util"
3229
"go.uber.org/zap/zapcore"
33-
"google.golang.org/protobuf/proto"
3430
)
3531

3632
var (
@@ -40,11 +36,12 @@ var (
4036
)
4137

4238
var (
43-
httpPort = flag.Int("port", 8080, "HTTP port to listen on")
44-
configHttpPort = flag.Int("config-port", 8081, "HTTP port for config endpoint (localhost only)")
45-
enclavePort = flag.Int("enclave-port", 5000, "VSOCK port the enclave is listening on")
46-
enclaveCID = flag.Int("enclave-cid", 16, "VSOCK CID of the enclave")
47-
quorumTimeout = flag.Duration("quorum-timeout", types.QuorumTimeout, "Timeout for waiting for quorum to be reached")
39+
httpPort = flag.Int("port", 8080, "HTTP port to listen on")
40+
configHttpPort = flag.Int("config-port", 8081, "HTTP port for config endpoint (localhost only)")
41+
enclavePort = flag.Int("enclave-port", 5000, "VSOCK port the enclave is listening on")
42+
enclaveCID = flag.Int("enclave-cid", 16, "VSOCK CID of the enclave")
43+
quorumTimeout = flag.Duration("quorum-timeout", types.QuorumTimeout, "Timeout for waiting for quorum to be reached")
44+
shutdownTimeout = flag.Duration("shutdown-timeout", 25*time.Second, "Maximum time to drain servers and flush telemetry during shutdown; keep below the process termination grace period")
4845
// requireBFTQuorum raises the batch quorum threshold from f+1 (one honest
4946
// node) to 2f+1 (a BFT supermajority). Reads REQUIRE_BFT_QUORUM.
5047
requireBFTQuorum = flag.Bool("require-bft-quorum", os.Getenv("REQUIRE_BFT_QUORUM") == "true", "require a 2f+1 BFT quorum instead of f+1. Reads REQUIRE_BFT_QUORUM.")
@@ -111,6 +108,7 @@ type hostServer struct {
111108
responseCache *util.Cache[*types.ExecuteResponse]
112109
verifier signatureverifier.SignatureVerifier
113110
logger cllogger.SugaredLogger
111+
metrics executionMetrics
114112
}
115113

116114
type batchRequest struct {
@@ -134,108 +132,6 @@ type batchResponse struct {
134132
err error
135133
}
136134

137-
func logPublicData(reqLog cllogger.SugaredLogger, appID string, publicData []byte) {
138-
switch appID {
139-
case types.AppIDConfidentialHTTP:
140-
var req confhttptypes.Request
141-
if err := proto.Unmarshal(publicData, &req); err != nil {
142-
reqLog.Warnw("failed to decode publicData",
143-
"event", "PUBLIC_DATA_DECODE_ERR",
144-
"appID", appID,
145-
"publicDataLen", len(publicData),
146-
"error", err)
147-
return
148-
}
149-
150-
bodyKind := "none"
151-
bodyLen := 0
152-
switch body := req.GetBody().(type) {
153-
case *confhttptypes.Request_BodyString:
154-
bodyKind = "string"
155-
bodyLen = len(body.BodyString)
156-
case *confhttptypes.Request_BodyBytes:
157-
bodyKind = "bytes"
158-
bodyLen = len(body.BodyBytes)
159-
}
160-
161-
timeout := ""
162-
if req.GetTimeout() != nil {
163-
timeout = req.GetTimeout().AsDuration().String()
164-
}
165-
166-
reqLog.Infow("decoded publicData",
167-
"event", "PUBLIC_DATA",
168-
"appID", appID,
169-
"publicDataLen", len(publicData),
170-
"publicDataType", "confidential_http_request",
171-
"url", req.GetUrl(),
172-
"method", req.GetMethod(),
173-
"bodyKind", bodyKind,
174-
"bodyLen", bodyLen,
175-
"headerNames", slices.Sorted(maps.Keys(req.GetMultiHeaders())),
176-
"templatePublicValueKeys", slices.Sorted(maps.Keys(req.GetTemplatePublicValues())),
177-
"customRootCACertPEMLen", len(req.GetCustomRootCaCertPem()),
178-
"timeout", timeout,
179-
"encryptOutput", req.GetEncryptOutput())
180-
181-
case types.AppIDConfidentialWorkflows:
182-
var execution confworkflowtypes.WorkflowExecution
183-
if err := proto.Unmarshal(publicData, &execution); err != nil {
184-
reqLog.Warnw("failed to decode publicData",
185-
"event", "PUBLIC_DATA_DECODE_ERR",
186-
"appID", appID,
187-
"publicDataLen", len(publicData),
188-
"error", err)
189-
return
190-
}
191-
192-
executeRequestKind := "unset"
193-
executeRequestConfigLen := 0
194-
var maxResponseSize uint64
195-
fields := []any{
196-
"event", "PUBLIC_DATA",
197-
"appID", appID,
198-
"publicDataLen", len(publicData),
199-
"publicDataType", "workflow_execution",
200-
"workflowID", execution.GetWorkflowId(),
201-
"executionID", execution.GetExecutionId(),
202-
"owner", execution.GetOwner(),
203-
"orgID", execution.GetOrgId(),
204-
"binaryURL", execution.GetBinaryUrl(),
205-
"binaryHash", hex.EncodeToString(execution.GetBinaryHash()),
206-
"requirementsPresent", execution.GetRequirements() != nil,
207-
"restrictionsPresent", execution.GetRestrictions() != nil,
208-
}
209-
210-
if execReq := execution.GetSdkExecuteRequest(); execReq != nil {
211-
executeRequestConfigLen = len(execReq.GetConfig())
212-
maxResponseSize = execReq.GetMaxResponseSize()
213-
switch req := execReq.GetRequest().(type) {
214-
case *sdkpb.ExecuteRequest_Subscribe:
215-
executeRequestKind = "subscribe"
216-
case *sdkpb.ExecuteRequest_Trigger:
217-
executeRequestKind = "trigger"
218-
fields = append(fields, "triggerID", req.Trigger.GetId())
219-
case *sdkpb.ExecuteRequest_PreHook:
220-
executeRequestKind = "pre_hook"
221-
fields = append(fields, "triggerID", req.PreHook.GetId())
222-
}
223-
}
224-
225-
fields = append(fields,
226-
"executeRequestKind", executeRequestKind,
227-
"executeRequestConfigLen", executeRequestConfigLen,
228-
"maxResponseSize", maxResponseSize)
229-
reqLog.Infow("decoded publicData", fields...)
230-
231-
default:
232-
reqLog.Debugw("publicData decoder unavailable",
233-
"event", "PUBLIC_DATA_UNSUPPORTED",
234-
"appID", appID,
235-
"publicDataLen", len(publicData))
236-
}
237-
}
238-
239135
func NewHostServer(ctx context.Context, clientOverride *http.Client) *hostServer {
240136
var client *http.Client
241137
if clientOverride == nil {
@@ -261,7 +157,8 @@ func NewHostServer(ctx context.Context, clientOverride *http.Client) *hostServer
261157
config: types.EnclaveConfig{},
262158
verifier: signatureverifier.NewEd25519SignatureVerifier(),
263159
// No-op by default so tests stay quiet; main injects the real logger.
264-
logger: cllogger.Sugared(cllogger.Nop()),
160+
logger: cllogger.Sugared(cllogger.Nop()),
161+
metrics: noopExecutionMetrics{},
265162
}
266163
}
267164

@@ -609,7 +506,7 @@ func (h *hostServer) handleExecute(w http.ResponseWriter, r *http.Request) {
609506
"ephemeralPK", ephemeralPKHex,
610507
"bodyLen", len(body),
611508
"arrivalTime", arrivalTime.Format(time.RFC3339Nano))
612-
logPublicData(reqLog, execReq.AppID, execReq.PublicData)
509+
metadata := inspectPublicData(reqLog, execReq.AppID, execReq.PublicData)
613510

614511
// Log hash input components for debugging hash divergence
615512
reqLog.Debugw("hash inputs",
@@ -766,9 +663,16 @@ func (h *hostServer) handleExecute(w http.ResponseWriter, r *http.Request) {
766663
"signers", signers,
767664
"signatureCount", len(requests))
768665
go func() {
666+
finishExecution := h.metrics.startExecution(metadata)
769667
enclaveStart := time.Now()
770668
resp, err := h.processBatch(requests)
771669
enclaveDuration := time.Since(enclaveStart)
670+
outcome := executionOutcomeSuccess
671+
if err != nil {
672+
outcome = executionOutcomeError
673+
}
674+
finishExecution(outcome)
675+
772676
if err != nil {
773677
reqLog.Errorw("enclave execution failed",
774678
"event", "ENCLAVE_ERR",
@@ -998,6 +902,9 @@ func main() {
998902
if *writeTimeout <= *quorumTimeout {
999903
log.Fatalf("write-timeout (%v) must be greater than quorum-timeout (%v)", *writeTimeout, *quorumTimeout)
1000904
}
905+
if *shutdownTimeout <= 0 {
906+
log.Fatalf("shutdown-timeout (%v) must be greater than zero", *shutdownTimeout)
907+
}
1001908

1002909
if *requireBFTQuorum {
1003910
lggr.Infow("BFT quorum required: batch threshold is 2f+1", "requireBFTQuorum", true)
@@ -1012,9 +919,23 @@ func main() {
1012919
sigCh := make(chan os.Signal, 1)
1013920
signal.Notify(sigCh, syscall.SIGTERM, syscall.SIGINT)
1014921

922+
telemetryCfg := loadHostTelemetryConfig(os.Getenv)
923+
telemetry, err := newHostTelemetry(ctx, telemetryCfg, lggr)
924+
if err != nil {
925+
log.Fatalf("failed to initialize telemetry: %v", err)
926+
}
927+
metrics, err := newHostMetrics(telemetry.meter)
928+
if err != nil {
929+
closeCtx, closeCancel := context.WithTimeout(context.Background(), *shutdownTimeout)
930+
_ = telemetry.close(closeCtx)
931+
closeCancel()
932+
log.Fatalf("failed to initialize host metrics: %v", err)
933+
}
934+
1015935
// Start servers. Optionally handle the config endpoint on a different port.
1016936
host := NewHostServer(ctx, nil)
1017937
host.logger = lggr
938+
host.metrics = metrics
1018939
mainMux := http.NewServeMux()
1019940

1020941
var configServer *http.Server
@@ -1109,7 +1030,7 @@ func main() {
11091030
cancel()
11101031

11111032
// Give pending requests time to complete
1112-
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 30*time.Second)
1033+
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), *shutdownTimeout)
11131034
defer shutdownCancel()
11141035

11151036
// Shutdown servers gracefully
@@ -1121,6 +1042,9 @@ func main() {
11211042
if err := mainServer.Shutdown(shutdownCtx); err != nil {
11221043
lggr.Errorw("main server shutdown error", "error", err)
11231044
}
1045+
if err := telemetry.close(shutdownCtx); err != nil {
1046+
lggr.Errorw("telemetry shutdown error", "error", err)
1047+
}
11241048

11251049
lggr.Infow("graceful shutdown complete")
11261050
}

0 commit comments

Comments
 (0)