Skip to content

Commit c4ef896

Browse files
authored
feat(prometheus): add histogram (#1141)
Signed-off-by: Miguel <[email protected]>
1 parent a16a8fb commit c4ef896

File tree

15 files changed

+191
-38
lines changed

15 files changed

+191
-38
lines changed

app/controlplane/cmd/wire_gen.go

Lines changed: 10 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/internal/server/grpc.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ func craftMiddleware(opts *Opts) []middleware.Middleware {
212212
// 2.a - Set its workflow and organization in the context
213213
usercontext.WithAttestationContextFromRobotAccount(opts.RobotAccountUseCase, opts.OrganizationUseCase, logHelper),
214214
// 2.b - Set its API token and Robot Account as alternative to the user
215-
usercontext.WithAttestationContextFromAPIToken(opts.APITokenUseCase, logHelper),
215+
usercontext.WithAttestationContextFromAPIToken(opts.APITokenUseCase, opts.OrganizationUseCase, logHelper),
216216
).Match(requireRobotAccountMatcher()).Build(),
217217
)
218218

app/controlplane/internal/service/attestation.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ type AttestationService struct {
5353
casMappingUseCase *biz.CASMappingUseCase
5454
referrerUseCase *biz.ReferrerUseCase
5555
orgUseCase *biz.OrganizationUseCase
56+
prometheusUseCase *biz.PrometheusUseCase
5657
}
5758

5859
type NewAttestationServiceOpts struct {
@@ -68,6 +69,7 @@ type NewAttestationServiceOpts struct {
6869
CASMappingUseCase *biz.CASMappingUseCase
6970
ReferrerUC *biz.ReferrerUseCase
7071
OrgUC *biz.OrganizationUseCase
72+
PromUC *biz.PrometheusUseCase
7173
Opts []NewOpt
7274
}
7375

@@ -86,6 +88,7 @@ func NewAttestationService(opts *NewAttestationServiceOpts) *AttestationService
8688
casMappingUseCase: opts.CASMappingUseCase,
8789
referrerUseCase: opts.ReferrerUC,
8890
orgUseCase: opts.OrgUC,
91+
prometheusUseCase: opts.PromUC,
8992
}
9093
}
9194

@@ -276,6 +279,9 @@ func (s *AttestationService) Store(ctx context.Context, req *cpAPI.AttestationSe
276279
return nil, handleUseCaseErr(err, s.log)
277280
}
278281

282+
// Record the attestation in the prometheus registry
283+
_ = s.prometheusUseCase.ObserveAttestationIfNeeded(ctx, wRun, biz.WorkflowRunSuccess)
284+
279285
return &cpAPI.AttestationServiceStoreResponse{
280286
Result: &cpAPI.AttestationServiceStoreResponse_Result{Digest: digest},
281287
}, nil
@@ -306,6 +312,16 @@ func (s *AttestationService) Cancel(ctx context.Context, req *cpAPI.AttestationS
306312
return nil, err
307313
}
308314

315+
wRun, err := s.wrUseCase.GetByIDInOrgOrPublic(ctx, robotAccount.OrgID, req.WorkflowRunId)
316+
if err != nil {
317+
return nil, handleUseCaseErr(err, s.log)
318+
} else if wRun == nil {
319+
return nil, errors.NotFound("not found", "workflow run not found")
320+
}
321+
322+
// Record the attestation in the prometheus registry
323+
_ = s.prometheusUseCase.ObserveAttestationIfNeeded(ctx, wRun, status)
324+
309325
return &cpAPI.AttestationServiceCancelResponse{}, nil
310326
}
311327

app/controlplane/internal/usercontext/apitoken_middleware.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func WithCurrentAPITokenAndOrgMiddleware(apiTokenUC *biz.APITokenUseCase, orgUC
103103
}
104104

105105
// WithAttestationContextFromAPIToken injects the API-Token, organization + robot account to the context
106-
func WithAttestationContextFromAPIToken(apiTokenUC *biz.APITokenUseCase, logger *log.Helper) middleware.Middleware {
106+
func WithAttestationContextFromAPIToken(apiTokenUC *biz.APITokenUseCase, orgUC *biz.OrganizationUseCase, logger *log.Helper) middleware.Middleware {
107107
return func(handler middleware.Handler) middleware.Handler {
108108
return func(ctx context.Context, req interface{}) (interface{}, error) {
109109
authInfo, ok := attjwtmiddleware.FromJWTAuthContext(ctx)
@@ -138,6 +138,11 @@ func WithAttestationContextFromAPIToken(apiTokenUC *biz.APITokenUseCase, logger
138138
return nil, fmt.Errorf("error extracting organization from APIToken: %w", err)
139139
}
140140

141+
ctx, err = setCurrentOrgAndAPIToken(ctx, apiTokenUC, orgUC, tokenID)
142+
if err != nil {
143+
return nil, fmt.Errorf("error setting current org and user: %w", err)
144+
}
145+
141146
logger.Infow("msg", "[authN] processed credentials", "id", tokenID, "type", "API-token")
142147

143148
return handler(ctx, req)

app/controlplane/pkg/biz/biz.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ var ProviderSet = wire.NewSet(
5050
NewAttestationStateUseCase,
5151
NewChainloopSigningUseCase,
5252
NewPrometheusUseCase,
53+
wire.Bind(new(PromObservable), new(*PrometheusUseCase)),
5354
wire.Struct(new(NewIntegrationUseCaseOpts), "*"),
5455
wire.Struct(new(NewUserUseCaseParams), "*"),
5556
)

app/controlplane/pkg/biz/mocks/PromObservable.go

Lines changed: 48 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/controlplane/pkg/biz/prometheus.go

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@
1616
package biz
1717

1818
import (
19+
"context"
20+
"time"
21+
1922
conf "github.com/chainloop-dev/chainloop/app/controlplane/internal/conf/controlplane/config/v1"
20-
"github.com/chainloop-dev/chainloop/app/controlplane/pkg/metrics/prometheus"
23+
chainloopprometheus "github.com/chainloop-dev/chainloop/app/controlplane/pkg/metrics/prometheus"
2124
"github.com/chainloop-dev/chainloop/app/controlplane/pkg/metrics/prometheus/registry"
25+
"github.com/prometheus/client_golang/prometheus"
2226

2327
"github.com/go-kratos/kratos/v2/log"
2428
)
@@ -30,7 +34,7 @@ type PrometheusUseCase struct {
3034
orgUseCase *OrganizationUseCase
3135
orgMetricsUseCase *OrgMetricsUseCase
3236
// Other
33-
registryManager *prometheus.ChainloopRegistryManager
37+
registryManager *chainloopprometheus.ChainloopRegistryManager
3438
}
3539

3640
// NewPrometheusUseCase creates a new PrometheusUseCase
@@ -48,15 +52,53 @@ func NewPrometheusUseCase(conf []*conf.PrometheusIntegrationSpec, orgUseCase *Or
4852
}
4953

5054
// loadPrometheusRegistries loads the prometheus registries from the configuration
51-
func loadPrometheusRegistries(conf []*conf.PrometheusIntegrationSpec, useCase *OrgMetricsUseCase, logger log.Logger) *prometheus.ChainloopRegistryManager {
52-
rm := prometheus.NewChainloopRegistryManager()
55+
func loadPrometheusRegistries(conf []*conf.PrometheusIntegrationSpec, useCase *OrgMetricsUseCase, logger log.Logger) *chainloopprometheus.ChainloopRegistryManager {
56+
manager := chainloopprometheus.NewChainloopRegistryManager()
5357

5458
for _, spec := range conf {
5559
reg := registry.NewPrometheusRegistry(spec.GetOrgName(), useCase, logger)
56-
rm.AddRegistry(reg)
60+
manager.AddRegistry(reg)
61+
}
62+
63+
return manager
64+
}
65+
66+
// Record an attestation if the run exists and there is a registry for the organization
67+
func (uc *PrometheusUseCase) ObserveAttestationIfNeeded(ctx context.Context, run *WorkflowRun, status WorkflowRunStatus) bool {
68+
if run == nil || run.Workflow == nil {
69+
return false
70+
}
71+
72+
workflow := run.Workflow
73+
orgID := workflow.OrgID
74+
75+
org, err := uc.orgUseCase.FindByID(ctx, orgID.String())
76+
if err != nil {
77+
return false
78+
}
79+
80+
if !uc.OrganizationHasRegistry(org.Name) {
81+
return false
82+
}
83+
84+
err = uc.observeAttestation(org.Name, workflow.Name, status, run.RunnerType, run.CreatedAt)
85+
return err == nil
86+
}
87+
88+
// OrganizationHasRegistry checks if an organization has a registry
89+
func (uc *PrometheusUseCase) observeAttestation(orgName, wfName string, status WorkflowRunStatus, runnerType string, startTime *time.Time) error {
90+
if orgName == "" || wfName == "" || status == "" || startTime == nil {
91+
return NewErrValidationStr("orgName, wfName, and state must be non-empty")
92+
}
93+
94+
reg := uc.GetRegistryByOrganizationName(orgName)
95+
if reg == nil {
96+
return NewErrNotFound("registry not found for organization")
5797
}
5898

59-
return rm
99+
duration := time.Since(*startTime).Seconds()
100+
reg.WorkflowRunDurationSeconds.With(prometheus.Labels{"org": orgName, "workflow": wfName, "status": string(status), "runner": runnerType}).Observe(duration)
101+
return nil
60102
}
61103

62104
// OrganizationHasRegistry checks if an organization has a registry

app/controlplane/pkg/biz/testhelpers/database.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ type TestingUseCases struct {
6262
WorkflowContract *biz.WorkflowContractUseCase
6363
Workflow *biz.WorkflowUseCase
6464
WorkflowRun *biz.WorkflowRunUseCase
65+
Prometheus *biz.PrometheusUseCase
6566
User *biz.UserUseCase
6667
RobotAccount *biz.RobotAccountUseCase
6768
RegisteredIntegrations sdk.AvailablePlugins
@@ -196,6 +197,10 @@ func NewConfData(db *TestDatabase, t *testing.T) *conf.Data {
196197
}
197198
}
198199

200+
func NewPromSpec() []*conf.PrometheusIntegrationSpec {
201+
return []*conf.PrometheusIntegrationSpec{}
202+
}
203+
199204
func NewDataConfig(in *conf.Data) *data.NewConfig {
200205
return &data.NewConfig{
201206
Driver: in.Database.Driver,

app/controlplane/pkg/biz/testhelpers/wire.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ func WireTestData(*TestDatabase, *testing.T, log.Logger, credentials.ReaderWrite
4747
wire.Struct(new(TestingRepos), "*"),
4848
NewConfData,
4949
NewDataConfig,
50+
NewPromSpec,
5051
authz.NewDatabaseEnforcer,
5152
wire.FieldsOf(new(*conf.Data), "Database"),
5253
),

app/controlplane/pkg/biz/testhelpers/wire_gen.go

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)