Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion configs/app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ profiler:
enabled: true
metrics:
statsd:
enabled: false
host: 127.0.0.1
port: 8125
telemetryDisabled: true
telemetryDisabled: false
prometheus:
enabled: true
host: 0.0.0.0
port: 9090
path: /metrics
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ require (
github.com/google/uuid v1.6.0
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.3
github.com/mdlayher/vsock v1.2.1
github.com/prometheus/client_golang v1.23.2
github.com/spf13/cobra v1.9.1
github.com/spf13/viper v1.21.0
github.com/stretchr/testify v1.11.1
Expand All @@ -30,6 +31,14 @@ require (
sigs.k8s.io/yaml v1.6.0
)

require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 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
)

require (
cel.dev/expr v0.25.1 // indirect
github.com/DataDog/gostackparse v0.7.0 // indirect
Expand Down
16 changes: 16 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.33.21 h1:nyLjs8sYJShFYj6aiyjCBI3EcLn
github.com/aws/aws-sdk-go-v2/service/sts v1.33.21/go.mod h1:EhdxtZ+g84MSGrSrHzZiUm9PYiZkrADNja15wtRJSJo=
github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM=
github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0=
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/brianvoe/gofakeit/v6 v6.28.0 h1:Xib46XXuQfmlLS2EXRuJpqcw8St6qSZz75OUo0tgAW4=
github.com/brianvoe/gofakeit/v6 v6.28.0/go.mod h1:Xj58BMSnFqcn/fAQeSK+/PLtC5kSb7FJIq4JyGa8vEs=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
Expand Down Expand Up @@ -149,10 +151,14 @@ 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/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
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/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/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a h1:3Bm7EwfUQUvhNeKIkUct/gl9eod1TcXuj8stxvi/GoI=
github.com/lufia/plan9stats v0.0.0-20240226150601-1dcf7310316a/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
Expand All @@ -166,6 +172,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
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/outcaste-io/ristretto v0.2.3 h1:AK4zt/fJ76kjlYObOeNwh4T3asEuaCmp26pOvUOL9w0=
github.com/outcaste-io/ristretto v0.2.3/go.mod h1:W8HywhmtlopSB1jeMg3JtdIhf+DYkLAr0VN/s4+MHac=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
Expand All @@ -181,6 +189,14 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU=
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs=
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/puzpuzpuz/xsync/v3 v3.5.1 h1:GJYJZwO6IdxN/IKbneznS6yPkVC+c3zyY/j19c++5Fg=
github.com/puzpuzpuz/xsync/v3 v3.5.1/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA=
github.com/richardartoul/molecule v1.0.1-0.20240531184615-7ca0df43c0b3 h1:4+LEVOB87y175cLJC/mbsgKmoDOjrBldtXvioEy96WY=
Expand Down
48 changes: 35 additions & 13 deletions internal/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"fmt"

"github.com/circlefin/arc-remote-signer/internal/app/metrics"
"github.com/circlefin/arc-remote-signer/internal/app/provider/awskms"
enclaveProvider "github.com/circlefin/arc-remote-signer/internal/app/provider/enclave"
"github.com/circlefin/arc-remote-signer/internal/app/provider/secrets"
Expand All @@ -32,8 +33,9 @@ import (
)

type metricProviders struct {
stats metric.StatsService
api metric.APIStatsService
stats metric.StatsService
api metric.APIStatsService
prometheus *metric.Prometheus
}

var _logger *logging.Logger
Expand Down Expand Up @@ -78,6 +80,10 @@ func Run(cfg *Config) {
logger.Info(ctx, "Profiler is not enabled", nil)
}

logger.Info(ctx, "initializing the metric services...", nil)
// init metrics here
appMetricProviders := initializeMetricsProviders(ctx, cfg.Metrics)

logger.Info(ctx, "initializing the providers...", nil)
enclavePvd, conn, err := enclaveProvider.New(cfg.Provider.Enclave)
if err != nil {
Expand Down Expand Up @@ -111,16 +117,12 @@ func Run(cfg *Config) {
}

logger.Info(ctx, "initializing the services...", nil)
signerSvc, err := signer.New(ctx, cfg.Provider.Enclave.NitroEnclave.Enabled, cfg.Service.Signer, secretPvd, enclavePvd, awskmsPvd)
signerSvc, err := signer.New(ctx, cfg.Provider.Enclave.NitroEnclave.Enabled, cfg.Service.Signer, secretPvd, enclavePvd, awskmsPvd, appMetricProviders.prometheus)
if err != nil {
logger.ErrorErr(ctx, "failed to initialize the signer service", err, nil)
panic(err)
}

logger.Info(ctx, "initializing the metric services...", nil)
// init metrics here
appMetricProviders := initializeMetricsProviders(ctx, cfg.Metrics)

lc := lifecycle.NewManager()

logger.Info(ctx, "initializing the server...", nil)
Expand All @@ -137,6 +139,15 @@ func Run(cfg *Config) {

lc.Manage(publicServer)

metricsServer, err := metrics.New(cfg.Metrics, appMetricProviders.prometheus)
if err != nil {
logger.ErrorErr(ctx, "failed to initialize the metrics server", err, nil)
panic(err)
}
if metricsServer != nil {
lc.Manage(metricsServer)
}

logger.Info(ctx, "run all runnable", nil)
lc.Run()
}
Expand All @@ -146,15 +157,26 @@ func initializeMetricsProviders(ctx context.Context, metricsCfg *metric.Config)
panic("metrics config unavailable")
}

statsService, err := metric.NewDatadogStatsD(metricsCfg.Statsd)
if err != nil {
getLogger().Error(ctx, "failed to initialize the metric service", logging.Entries{"error": err})
panic(err)
var statsService metric.StatsService
var apiStatsService metric.APIStatsService
if metricsCfg.IsStatsdEnabled() {
statsService, err := metric.NewDatadogStatsD(metricsCfg.Statsd)
if err != nil {
getLogger().Error(ctx, "failed to initialize the metric service", logging.Entries{"error": err})
panic(err)
}
apiStatsService = metric.NewAPIStatsServiceImpl(statsService, metric.WithDistributionsOption(metric.DistributionsEnabled))
}

var prometheus *metric.Prometheus
if metricsCfg.IsPrometheusEnabled() {
prometheus = metric.NewPrometheus()
}

return metricProviders{
stats: statsService,
api: metric.NewAPIStatsServiceImpl(statsService, metric.WithDistributionsOption(metric.DistributionsEnabled)),
stats: statsService,
api: apiStatsService,
prometheus: prometheus,
}
}

Expand Down
49 changes: 49 additions & 0 deletions internal/app/metrics/metrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Copyright (c) 2026, Circle Internet Group, Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package metrics provides the metrics for the app service.
package metrics

import "github.com/circlefin/arc-remote-signer/internal/common/metric"

const (
// RequestTotalCounter is the total number of requests.
RequestTotalCounter = "arc_remote_signer_request_total"

// RequestTotalCounterSuccess is the total number of successful requests.
RequestTotalCounterSuccess = "arc_remote_signer_request_total_success"

// RequestTotalCounterError is the total number of error requests.
RequestTotalCounterError = "arc_remote_signer_request_total_error"
)

var metrics = []metric.PrometheusMetric{
{
Name: RequestTotalCounter,
Help: "Total number of signing requests",
Type: "counterVec",
Labels: []string{"type"},
},
{
Name: RequestTotalCounterSuccess,
Help: "Total number of successful signing requests",
Type: "counterVec",
Labels: []string{"type"},
},
{
Name: RequestTotalCounterError,
Help: "Total number of failed signing requests",
Type: "counterVec",
Labels: []string{"type"},
},
}
52 changes: 52 additions & 0 deletions internal/app/metrics/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) 2026, Circle Internet Group, Inc.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package metrics

import (
"fmt"
"log"
"net/http"

"github.com/circlefin/arc-remote-signer/internal/common/http/server"
"github.com/circlefin/arc-remote-signer/internal/common/lifecycle"
"github.com/circlefin/arc-remote-signer/internal/common/metric"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

// New creates a new metrics server that implements lifecycle.Runnable.
func New(cfg *metric.Config, prometheus *metric.Prometheus) (lifecycle.Runnable, error) {
if cfg == nil || cfg.Prometheus == nil || !cfg.Prometheus.Enabled {
return nil, nil
}

if prometheus == nil {
return nil, fmt.Errorf("prometheus is not initialized")
}

// register metrics
log.Printf("registering metrics...")
for _, metric := range metrics {
prometheus.Register(metric)
}

promHandler := promhttp.InstrumentMetricHandler(prometheus.Registry(), promhttp.HandlerFor(prometheus.Registry(), promhttp.HandlerOpts{}))
path := cfg.Prometheus.GetPath()
mux := http.NewServeMux()
mux.Handle(path, promHandler)

metricsServer := server.NewServer(server.RequiredEngineParams{
ServerName: "metrics",
}, mux)
return server.NewRunnable("metrics", metricsServer, server.WithListener(cfg.Prometheus.Host, cfg.Prometheus.Port))
}
9 changes: 8 additions & 1 deletion internal/app/public/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package public

import (
"fmt"

"github.com/circlefin/arc-remote-signer/internal/common/config"
grpcServer "github.com/circlefin/arc-remote-signer/internal/common/grpc/server"
"github.com/circlefin/arc-remote-signer/internal/common/lifecycle"
Expand All @@ -33,11 +35,16 @@ type CreateServerParams struct {

// New creates a new public server that implements lifecycle.Runnable for the app service.
func New(cfg *grpcServer.Config, params CreateServerParams) (lifecycle.Runnable, error) {
opts, err := grpcServer.WithTLS(cfg.TLS)
if err != nil {
return nil, fmt.Errorf("failed to load TLS options: %w", err)
}

grpcSrv := grpcServer.NewServer(grpcServer.RequiredEngineParams{
ServiceName: params.ServiceName,
Env: params.Env,
APIStatsService: params.APIStatsSvc,
})
}, opts...)
reflection.Register(grpcSrv)
pb.RegisterSignerServiceServer(grpcSrv, params.SignerSvc)

Expand Down
Loading