2021-05-05 00:41:13 +05:30
package metrics
import (
2022-07-11 23:19:47 +05:30
"context"
"net/http"
"time"
2021-09-11 03:09:12 +05:30
2022-07-11 23:19:47 +05:30
"github.com/go-logr/logr"
2022-12-09 10:49:45 +01:00
"github.com/kyverno/kyverno/pkg/config"
2022-07-11 23:19:47 +05:30
kconfig "github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/utils/kube"
2022-12-06 16:41:00 +01:00
"github.com/kyverno/kyverno/pkg/version"
"github.com/prometheus/client_golang/prometheus/promhttp"
2022-07-25 14:55:26 +05:30
"go.opentelemetry.io/otel"
2022-07-11 23:19:47 +05:30
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
"go.opentelemetry.io/otel/exporters/prometheus"
2022-12-06 16:41:00 +01:00
"go.opentelemetry.io/otel/metric"
2022-07-11 23:19:47 +05:30
"go.opentelemetry.io/otel/metric/instrument"
"go.opentelemetry.io/otel/metric/instrument/syncfloat64"
"go.opentelemetry.io/otel/metric/instrument/syncint64"
2022-12-06 16:41:00 +01:00
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
2022-07-11 23:19:47 +05:30
"go.opentelemetry.io/otel/sdk/resource"
2022-12-06 16:41:00 +01:00
semconv "go.opentelemetry.io/otel/semconv/v1.12.0"
2022-07-11 23:19:47 +05:30
"k8s.io/client-go/kubernetes"
2021-05-05 00:41:13 +05:30
)
2022-07-11 23:19:47 +05:30
const (
2022-11-29 13:16:15 +01:00
MeterName = "kyverno"
2022-07-11 23:19:47 +05:30
)
type MetricsConfig struct {
// instruments
policyChangesMetric syncint64 . Counter
policyResultsMetric syncint64 . Counter
policyExecutionDurationMetric syncfloat64 . Histogram
2022-08-31 14:03:47 +08:00
clientQueriesMetric syncint64 . Counter
2022-07-11 23:19:47 +05:30
// config
2022-11-30 14:37:53 +01:00
config kconfig . MetricsConfiguration
2022-07-11 23:19:47 +05:30
Log logr . Logger
2021-05-05 00:41:13 +05:30
}
2022-08-31 14:03:47 +08:00
type MetricsConfigManager interface {
2022-11-30 14:37:53 +01:00
Config ( ) kconfig . MetricsConfiguration
2022-11-28 11:30:14 +01:00
RecordPolicyResults ( ctx context . Context , policyValidationMode PolicyValidationMode , policyType PolicyType , policyBackgroundMode PolicyBackgroundMode , policyNamespace string , policyName string , resourceKind string , resourceNamespace string , resourceRequestOperation ResourceRequestOperation , ruleName string , ruleResult RuleResult , ruleType RuleType , ruleExecutionCause RuleExecutionCause )
RecordPolicyChanges ( ctx context . Context , policyValidationMode PolicyValidationMode , policyType PolicyType , policyBackgroundMode PolicyBackgroundMode , policyNamespace string , policyName string , policyChangeType string )
RecordPolicyExecutionDuration ( ctx context . Context , policyValidationMode PolicyValidationMode , policyType PolicyType , policyBackgroundMode PolicyBackgroundMode , policyNamespace string , policyName string , ruleName string , ruleResult RuleResult , ruleType RuleType , ruleExecutionCause RuleExecutionCause , ruleExecutionLatency float64 )
RecordClientQueries ( ctx context . Context , clientQueryOperation ClientQueryOperation , clientType ClientType , resourceKind string , resourceNamespace string )
2022-08-31 14:03:47 +08:00
}
2022-11-30 14:37:53 +01:00
func ( m * MetricsConfig ) Config ( ) kconfig . MetricsConfiguration {
return m . config
}
2022-12-06 16:41:00 +01:00
func ( m * MetricsConfig ) initializeMetrics ( meterProvider metric . MeterProvider ) error {
2022-07-11 23:19:47 +05:30
var err error
2022-12-06 16:41:00 +01:00
meter := meterProvider . Meter ( MeterName )
m . policyResultsMetric , err = meter . SyncInt64 ( ) . Counter ( "kyverno_policy_results" , instrument . WithDescription ( "can be used to track the results associated with the policies applied in the user’ s cluster, at the level from rule to policy to admission requests" ) )
2022-07-11 23:19:47 +05:30
if err != nil {
2022-12-06 16:41:00 +01:00
m . Log . Error ( err , "Failed to create instrument, kyverno_policy_results" )
2022-11-25 14:14:55 +01:00
return err
2022-07-11 23:19:47 +05:30
}
2022-12-06 16:41:00 +01:00
m . policyChangesMetric , err = meter . SyncInt64 ( ) . Counter ( "kyverno_policy_changes" , instrument . WithDescription ( "can be used to track all the changes associated with the Kyverno policies present on the cluster such as creation, updates and deletions" ) )
2022-07-11 23:19:47 +05:30
if err != nil {
2022-12-06 16:41:00 +01:00
m . Log . Error ( err , "Failed to create instrument, kyverno_policy_changes" )
2022-11-25 14:14:55 +01:00
return err
2022-07-11 23:19:47 +05:30
}
m . policyExecutionDurationMetric , err = meter . SyncFloat64 ( ) . Histogram ( "kyverno_policy_execution_duration_seconds" , instrument . WithDescription ( "can be used to track the latencies (in seconds) associated with the execution/processing of the individual rules under Kyverno policies whenever they evaluate incoming resource requests" ) )
if err != nil {
2022-08-31 14:03:47 +08:00
m . Log . Error ( err , "Failed to create instrument, kyverno_policy_execution_duration_seconds" )
2022-11-25 14:14:55 +01:00
return err
2022-07-11 23:19:47 +05:30
}
2022-12-06 16:41:00 +01:00
m . clientQueriesMetric , err = meter . SyncInt64 ( ) . Counter ( "kyverno_client_queries" , instrument . WithDescription ( "can be used to track the number of client queries sent from Kyverno to the API-server" ) )
2022-07-11 23:19:47 +05:30
if err != nil {
2022-12-06 16:41:00 +01:00
m . Log . Error ( err , "Failed to create instrument, kyverno_client_queries" )
2022-11-25 14:14:55 +01:00
return err
2022-08-31 14:03:47 +08:00
}
2022-11-25 14:14:55 +01:00
return nil
2021-05-05 00:41:13 +05:30
}
2022-12-06 16:41:00 +01:00
func ShutDownController ( ctx context . Context , pusher * sdkmetric . MeterProvider ) {
2022-11-17 06:29:32 +01:00
if pusher != nil {
// pushes any last exports to the receiver
2022-12-06 16:41:00 +01:00
if err := pusher . Shutdown ( ctx ) ; err != nil {
2022-11-17 06:29:32 +01:00
otel . Handle ( err )
}
2022-07-25 14:55:26 +05:30
}
}
2022-11-17 06:29:32 +01:00
func NewOTLPGRPCConfig (
2022-11-28 11:30:14 +01:00
ctx context . Context ,
2022-11-17 06:29:32 +01:00
endpoint string ,
2022-07-11 23:19:47 +05:30
certs string ,
kubeClient kubernetes . Interface ,
log logr . Logger ,
2022-12-06 16:41:00 +01:00
) ( metric . MeterProvider , error ) {
options := [ ] otlpmetricgrpc . Option { otlpmetricgrpc . WithEndpoint ( endpoint ) }
2022-07-11 23:19:47 +05:30
if certs != "" {
// here the certificates are stored as configmaps
transportCreds , err := kube . FetchCert ( ctx , certs , kubeClient )
if err != nil {
log . Error ( err , "Error fetching certificate from secret" )
2022-11-17 06:29:32 +01:00
return nil , err
2022-07-11 23:19:47 +05:30
}
2022-12-06 16:41:00 +01:00
options = append ( options , otlpmetricgrpc . WithTLSCredentials ( transportCreds ) )
2022-07-11 23:19:47 +05:30
} else {
2022-12-06 16:41:00 +01:00
options = append ( options , otlpmetricgrpc . WithInsecure ( ) )
2021-05-05 00:41:13 +05:30
}
2022-12-06 16:41:00 +01:00
// create new exporter for exporting metrics
exporter , err := otlpmetricgrpc . New ( ctx , options ... )
2022-07-11 23:19:47 +05:30
if err != nil {
log . Error ( err , "Failed to create the collector exporter" )
2022-11-17 06:29:32 +01:00
return nil , err
2021-05-05 00:41:13 +05:30
}
2022-12-06 16:41:00 +01:00
res , err := resource . Merge (
resource . Default ( ) ,
resource . NewWithAttributes (
semconv . SchemaURL ,
2022-12-09 10:49:45 +01:00
semconv . ServiceNameKey . String ( MeterName ) ,
2022-12-06 16:41:00 +01:00
semconv . ServiceVersionKey . String ( version . BuildVersion ) ,
) ,
2021-05-05 00:41:13 +05:30
)
2022-07-11 23:19:47 +05:30
if err != nil {
log . Error ( err , "failed creating resource" )
2022-11-17 06:29:32 +01:00
return nil , err
2022-07-11 23:19:47 +05:30
}
2022-12-06 16:41:00 +01:00
reader := sdkmetric . NewPeriodicReader (
exporter ,
sdkmetric . WithInterval ( 2 * time . Second ) ,
)
2022-07-11 23:19:47 +05:30
// create controller and bind the exporter with it
2022-12-06 16:41:00 +01:00
provider := sdkmetric . NewMeterProvider (
sdkmetric . WithReader ( reader ) ,
sdkmetric . WithResource ( res ) ,
2021-05-05 00:41:13 +05:30
)
2022-12-06 16:41:00 +01:00
return provider , nil
2022-07-11 23:19:47 +05:30
}
2022-11-17 06:29:32 +01:00
func NewPrometheusConfig (
2022-11-28 11:30:14 +01:00
ctx context . Context ,
2022-07-11 23:19:47 +05:30
log logr . Logger ,
2022-12-06 16:41:00 +01:00
) ( metric . MeterProvider , * http . ServeMux , error ) {
res , err := resource . Merge (
resource . Default ( ) ,
resource . NewWithAttributes (
semconv . SchemaURL ,
semconv . ServiceNameKey . String ( "kyverno-svc-metrics" ) ,
semconv . ServiceNamespaceKey . String ( kconfig . KyvernoNamespace ( ) ) ,
semconv . ServiceVersionKey . String ( version . BuildVersion ) ,
) ,
2021-05-05 00:41:13 +05:30
)
2022-07-11 23:19:47 +05:30
if err != nil {
log . Error ( err , "failed creating resource" )
2022-12-06 16:41:00 +01:00
return nil , nil , err
2022-07-11 23:19:47 +05:30
}
2022-12-06 16:41:00 +01:00
exporter , err := prometheus . New (
prometheus . WithoutUnits ( ) ,
prometheus . WithoutTargetInfo ( ) ,
2022-07-11 23:19:47 +05:30
)
if err != nil {
log . Error ( err , "failed to initialize prometheus exporter" )
2022-12-06 16:41:00 +01:00
return nil , nil , err
2022-07-11 23:19:47 +05:30
}
2022-12-06 16:41:00 +01:00
provider := sdkmetric . NewMeterProvider (
sdkmetric . WithReader ( exporter ) ,
sdkmetric . WithResource ( res ) ,
)
2022-07-11 23:19:47 +05:30
metricsServerMux := http . NewServeMux ( )
2022-12-09 10:49:45 +01:00
metricsServerMux . Handle ( config . MetricsPath , promhttp . Handler ( ) )
2022-12-06 16:41:00 +01:00
return provider , metricsServerMux , nil
2022-07-11 23:19:47 +05:30
}
2022-11-28 11:30:14 +01:00
func ( m * MetricsConfig ) RecordPolicyResults ( ctx context . Context , policyValidationMode PolicyValidationMode , policyType PolicyType , policyBackgroundMode PolicyBackgroundMode , policyNamespace string , policyName string ,
2022-07-11 23:19:47 +05:30
resourceKind string , resourceNamespace string , resourceRequestOperation ResourceRequestOperation , ruleName string , ruleResult RuleResult , ruleType RuleType ,
2022-08-24 15:08:24 +02:00
ruleExecutionCause RuleExecutionCause ,
) {
2022-07-11 23:19:47 +05:30
commonLabels := [ ] attribute . KeyValue {
attribute . String ( "policy_validation_mode" , string ( policyValidationMode ) ) ,
attribute . String ( "policy_type" , string ( policyType ) ) ,
attribute . String ( "policy_background_mode" , string ( policyBackgroundMode ) ) ,
attribute . String ( "policy_namespace" , policyNamespace ) ,
attribute . String ( "policy_name" , policyName ) ,
attribute . String ( "resource_kind" , resourceKind ) ,
attribute . String ( "resource_namespace" , resourceNamespace ) ,
attribute . String ( "resource_request_operation" , string ( resourceRequestOperation ) ) ,
attribute . String ( "rule_name" , ruleName ) ,
attribute . String ( "rule_result" , string ( ruleResult ) ) ,
attribute . String ( "rule_type" , string ( ruleType ) ) ,
attribute . String ( "rule_execution_cause" , string ( ruleExecutionCause ) ) ,
}
m . policyResultsMetric . Add ( ctx , 1 , commonLabels ... )
}
2022-11-28 11:30:14 +01:00
func ( m * MetricsConfig ) RecordPolicyChanges ( ctx context . Context , policyValidationMode PolicyValidationMode , policyType PolicyType , policyBackgroundMode PolicyBackgroundMode , policyNamespace string , policyName string , policyChangeType string ) {
2022-07-11 23:19:47 +05:30
commonLabels := [ ] attribute . KeyValue {
attribute . String ( "policy_validation_mode" , string ( policyValidationMode ) ) ,
attribute . String ( "policy_type" , string ( policyType ) ) ,
attribute . String ( "policy_background_mode" , string ( policyBackgroundMode ) ) ,
attribute . String ( "policy_namespace" , policyNamespace ) ,
attribute . String ( "policy_name" , policyName ) ,
attribute . String ( "policy_change_type" , policyChangeType ) ,
}
m . policyChangesMetric . Add ( ctx , 1 , commonLabels ... )
}
2022-11-28 11:30:14 +01:00
func ( m * MetricsConfig ) RecordPolicyExecutionDuration ( ctx context . Context , policyValidationMode PolicyValidationMode , policyType PolicyType , policyBackgroundMode PolicyBackgroundMode , policyNamespace string , policyName string ,
2022-11-04 14:31:23 +08:00
ruleName string , ruleResult RuleResult , ruleType RuleType , ruleExecutionCause RuleExecutionCause , ruleExecutionLatency float64 ,
2022-08-24 15:08:24 +02:00
) {
2022-07-11 23:19:47 +05:30
commonLabels := [ ] attribute . KeyValue {
attribute . String ( "policy_validation_mode" , string ( policyValidationMode ) ) ,
attribute . String ( "policy_type" , string ( policyType ) ) ,
attribute . String ( "policy_background_mode" , string ( policyBackgroundMode ) ) ,
attribute . String ( "policy_namespace" , policyNamespace ) ,
attribute . String ( "policy_name" , policyName ) ,
attribute . String ( "rule_name" , ruleName ) ,
attribute . String ( "rule_result" , string ( ruleResult ) ) ,
attribute . String ( "rule_type" , string ( ruleType ) ) ,
attribute . String ( "rule_execution_cause" , string ( ruleExecutionCause ) ) ,
}
m . policyExecutionDurationMetric . Record ( ctx , ruleExecutionLatency , commonLabels ... )
}
2022-11-28 11:30:14 +01:00
func ( m * MetricsConfig ) RecordClientQueries ( ctx context . Context , clientQueryOperation ClientQueryOperation , clientType ClientType , resourceKind string , resourceNamespace string ) {
2022-08-31 14:03:47 +08:00
commonLabels := [ ] attribute . KeyValue {
attribute . String ( "operation" , string ( clientQueryOperation ) ) ,
attribute . String ( "client_type" , string ( clientType ) ) ,
attribute . String ( "resource_kind" , resourceKind ) ,
attribute . String ( "resource_namespace" , resourceNamespace ) ,
}
m . clientQueriesMetric . Add ( ctx , 1 , commonLabels ... )
}