1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

feat: make traces better (#5412)

* feat: make traces better

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

* error

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>

Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
Charles-Edouard Brétéché 2022-11-20 14:42:57 +01:00 committed by GitHub
parent 4bdd45c0cc
commit ce94187bd3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 9224 additions and 3458 deletions

View file

@ -20,10 +20,23 @@ var (
)
type arg struct {
Type reflect.Type
reflect.Type
IsVariadic bool
}
func (a arg) IsError() bool {
return goType(a.Type) == "error"
}
type ret struct {
reflect.Type
IsLast bool
}
func (r ret) IsError() bool {
return goType(r.Type) == "error"
}
type operation struct {
Method reflect.Method
}
@ -32,6 +45,10 @@ func (o operation) HasContext() bool {
return o.Method.Type.NumIn() > 0 && goType(o.Method.Type.In(0)) == "context.Context"
}
func (o operation) HasError() bool {
return o.Method.Type.NumIn() > 0 && goType(o.Method.Type.In(o.Method.Type.NumIn()-1)) == "error"
}
type resource struct {
Method reflect.Method
Type reflect.Type
@ -65,10 +82,13 @@ func getIns(in reflect.Method) []reflect.Type {
return out
}
func getOuts(in reflect.Method) []reflect.Type {
var out []reflect.Type
func getOuts(in reflect.Method) []ret {
var out []ret
for i := 0; i < in.Type.NumOut(); i++ {
out = append(out, in.Type.Out(i))
out = append(out, ret{
Type: in.Type.Out(i),
IsLast: i == in.Type.NumOut()-1,
})
}
return out
}
@ -164,10 +184,11 @@ func parseImports(cs clientset, packages ...string) []string {
}
}
for _, i := range getOuts(o.Method) {
pkg := i.PkgPath()
if i.Kind() == reflect.Pointer {
i = i.Elem()
i.Elem().PkgPath()
}
if i.PkgPath() != "" {
if pkg != "" {
imports.Insert(i.PkgPath())
}
}
@ -200,7 +221,7 @@ func executeTemplate(tpl string, cs clientset, folder string, packages ...string
}
return out
},
"Returns": func(in reflect.Method) []reflect.Type {
"Returns": func(in reflect.Method) []ret {
return getOuts(in)
},
"Pkg": func(in string) string {
@ -223,6 +244,7 @@ func executeTemplate(tpl string, cs clientset, folder string, packages ...string
panic(fmt.Sprintf("Failed to create file %s", path.Join(folder, file)))
}
if err := tmpl.Execute(f, map[string]interface{}{
"Folder": folder,
"Clientset": cs,
"Packages": parseImports(cs, packages...),
}); err != nil {
@ -359,6 +381,7 @@ package client
{{- $restPkg := Pkg "k8s.io/client-go/rest" }}
{{- $tracingPkg := Pkg "github.com/kyverno/kyverno/pkg/tracing" }}
{{- $attributePkg := Pkg "go.opentelemetry.io/otel/attribute" }}
{{- $codesPkg := Pkg "go.opentelemetry.io/otel/codes" }}
import (
{{- range $package := .Packages }}
@ -452,8 +475,8 @@ func (c *wrapped{{ $client.Method.Name }}{{ $resource.Method.Name }}) {{ $operat
{{- if $operation.HasContext }}
ctx, span := {{ $tracingPkg }}.StartSpan(
arg0,
"{{ $client.Method.Name }}/{{ $resource.Method.Name }}",
{{ Quote $operation.Method.Name }},
{{ Quote $.Folder }},
"KUBE {{ $client.Method.Name }}/{{ $resource.Method.Name }}/{{ $operation.Method.Name }}",
{{ $attributePkg }}.String("client", {{ Quote $client.Method.Name }}),
{{ $attributePkg }}.String("resource", {{ Quote $resource.Method.Name }}),
{{ $attributePkg }}.String("kind", {{ Quote $resource.Kind }}),
@ -461,7 +484,7 @@ func (c *wrapped{{ $client.Method.Name }}{{ $resource.Method.Name }}) {{ $operat
defer span.End()
arg0 = ctx
{{- end }}
return c.inner.{{ $operation.Method.Name }}(
{{ range $i, $ret := Returns $operation.Method }}ret{{ $i }}{{ if not $ret.IsLast -}},{{- end }} {{ end }} := c.inner.{{ $operation.Method.Name }}(
{{- range $i, $arg := Args $operation.Method -}}
{{- if $arg.IsVariadic -}}
arg{{ $i }}...,
@ -470,6 +493,19 @@ func (c *wrapped{{ $client.Method.Name }}{{ $resource.Method.Name }}) {{ $operat
{{- end -}}
{{- end -}}
)
{{- if $operation.HasContext }}
{{- range $i, $ret := Returns $operation.Method }}
{{- if $ret.IsError }}
if ret{{ $i }} != nil {
span.RecordError(ret{{ $i }})
span.SetStatus({{ $codesPkg }}.Ok, ret{{ $i }}.Error())
}
{{- end }}
{{- end }}
{{- end }}
return {{ range $i, $ret := Returns $operation.Method -}}
ret{{ $i }}{{ if not $ret.IsLast -}},{{- end }}
{{- end }}
}
{{- end }}
{{- end }}
@ -503,6 +539,7 @@ func main() {
"context",
"github.com/kyverno/kyverno/pkg/tracing",
"go.opentelemetry.io/otel/attribute",
"go.opentelemetry.io/otel/codes",
"k8s.io/client-go/discovery",
"k8s.io/client-go/rest",
)
@ -512,6 +549,7 @@ func main() {
"context",
"github.com/kyverno/kyverno/pkg/tracing",
"go.opentelemetry.io/otel/attribute",
"go.opentelemetry.io/otel/codes",
"k8s.io/client-go/discovery",
"k8s.io/client-go/rest",
)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,6 @@
package handlers
import (
"context"
"encoding/json"
"fmt"
"io"
@ -10,15 +9,9 @@ import (
"github.com/go-logr/logr"
"github.com/kyverno/kyverno/pkg/tracing"
"go.opentelemetry.io/otel/attribute"
admissionv1 "k8s.io/api/admission/v1"
)
type (
AdmissionHandler func(context.Context, logr.Logger, *admissionv1.AdmissionRequest, time.Time) *admissionv1.AdmissionResponse
HttpHandler func(http.ResponseWriter, *http.Request)
)
func (h AdmissionHandler) WithAdmission(logger logr.Logger) HttpHandler {
return withAdmission(logger, h)
}
@ -65,13 +58,9 @@ func withAdmission(logger logr.Logger, inner AdmissionHandler) HttpHandler {
// start span from request context
ctx, span := tracing.StartSpan(
request.Context(),
"admission_webhook_operations",
string(admissionReview.Request.Operation),
attribute.String("kind", admissionReview.Request.Kind.Kind),
attribute.String("namespace", admissionReview.Request.Namespace),
attribute.String("name", admissionReview.Request.Name),
attribute.String("operation", string(admissionReview.Request.Operation)),
attribute.String("uid", string(admissionReview.Request.UID)),
"webhooks/handlers",
fmt.Sprintf("ADMISSION %s %s", admissionReview.Request.Operation, admissionReview.Request.Kind),
admissionRequestAttributes(admissionReview.Request)...,
)
defer span.End()
adminssionResponse := inner(ctx, logger, admissionReview.Request, startTime)

View file

@ -2,6 +2,7 @@ package handlers
import (
"context"
"fmt"
"strings"
"time"
@ -107,13 +108,14 @@ func withDump(inner AdmissionHandler) AdmissionHandler {
return func(ctx context.Context, logger logr.Logger, request *admissionv1.AdmissionRequest, startTime time.Time) *admissionv1.AdmissionResponse {
return tracing.Span1(
ctx,
"admission_webhook_operations",
"dump",
"webhooks/handlers",
fmt.Sprintf("DUMP %s %s", request.Operation, request.Kind),
func(ctx context.Context, span trace.Span) *admissionv1.AdmissionResponse {
response := inner(ctx, logger, request, startTime)
dumpPayload(logger, request, response)
return response
},
trace.WithAttributes(admissionRequestAttributes(request)...),
)
}
}

View file

@ -2,6 +2,7 @@ package handlers
import (
"context"
"fmt"
"time"
"github.com/go-logr/logr"
@ -19,14 +20,15 @@ func withFilter(c config.Configuration, inner AdmissionHandler) AdmissionHandler
return func(ctx context.Context, logger logr.Logger, request *admissionv1.AdmissionRequest, startTime time.Time) *admissionv1.AdmissionResponse {
return tracing.Span1(
ctx,
"admission_webhook_operations",
"filter",
"webhooks/handlers",
fmt.Sprintf("FILTER %s %s", request.Operation, request.Kind),
func(ctx context.Context, span trace.Span) *admissionv1.AdmissionResponse {
if c.ToFilter(request.Kind.Kind, request.Namespace, request.Name) {
return nil
}
return inner(ctx, logger, request, startTime)
},
trace.WithAttributes(admissionRequestAttributes(request)...),
)
}
}

View file

@ -2,6 +2,7 @@ package handlers
import (
"context"
"fmt"
"time"
"github.com/go-logr/logr"
@ -21,13 +22,14 @@ func withMetrics(metricsConfig *metrics.MetricsConfig, inner AdmissionHandler) A
return func(ctx context.Context, logger logr.Logger, request *admissionv1.AdmissionRequest, startTime time.Time) *admissionv1.AdmissionResponse {
return tracing.Span1(
ctx,
"admission_webhook_operations",
"metrics",
"webhooks/handlers",
fmt.Sprintf("METRICS %s %s", request.Operation, request.Kind),
func(ctx context.Context, span trace.Span) *admissionv1.AdmissionResponse {
defer admissionReviewDuration.Process(metricsConfig, request, int64(time.Since(startTime)))
admissionRequests.Process(metricsConfig, request)
return inner(ctx, logger, request, startTime)
},
trace.WithAttributes(admissionRequestAttributes(request)...),
)
}
}

View file

@ -28,8 +28,8 @@ func withProtection(inner AdmissionHandler) AdmissionHandler {
return func(ctx context.Context, logger logr.Logger, request *admissionv1.AdmissionRequest, startTime time.Time) *admissionv1.AdmissionResponse {
return tracing.Span1(
ctx,
"admission_webhook_operations",
"protect",
"webhooks/handlers",
fmt.Sprintf("PROTECT %s %s", request.Operation, request.Kind),
func(ctx context.Context, span trace.Span) *admissionv1.AdmissionResponse {
newResource, oldResource, err := utils.ExtractResources(nil, request)
if err != nil {
@ -47,6 +47,7 @@ func withProtection(inner AdmissionHandler) AdmissionHandler {
}
return inner(ctx, logger, request, startTime)
},
trace.WithAttributes(admissionRequestAttributes(request)...),
)
}
}

View file

@ -2,6 +2,7 @@ package handlers
import (
"context"
"fmt"
"net/http"
"github.com/kyverno/kyverno/pkg/tracing"
@ -17,8 +18,8 @@ func withTrace(inner HttpHandler) HttpHandler {
return func(writer http.ResponseWriter, request *http.Request) {
tracing.Span(
request.Context(),
"admission_webhook_operations",
request.URL.Path,
"webhooks/handlers",
fmt.Sprintf("HTTP %s %s", request.Method, request.URL.Path),
func(ctx context.Context, span trace.Span) {
inner(writer, request.WithContext(ctx))
},

View file

@ -0,0 +1,15 @@
package handlers
import (
"context"
"net/http"
"time"
"github.com/go-logr/logr"
admissionv1 "k8s.io/api/admission/v1"
)
type (
AdmissionHandler func(context.Context, logr.Logger, *admissionv1.AdmissionRequest, time.Time) *admissionv1.AdmissionResponse
HttpHandler func(http.ResponseWriter, *http.Request)
)

View file

@ -0,0 +1,16 @@
package handlers
import (
"go.opentelemetry.io/otel/attribute"
admissionv1 "k8s.io/api/admission/v1"
)
func admissionRequestAttributes(request *admissionv1.AdmissionRequest) []attribute.KeyValue {
return []attribute.KeyValue{
attribute.String("kind", request.Kind.Kind),
attribute.String("namespace", request.Namespace),
attribute.String("name", request.Name),
attribute.String("operation", string(request.Operation)),
attribute.String("uid", string(request.UID)),
}
}

View file

@ -2,6 +2,7 @@ package handlers
import (
"context"
"fmt"
"time"
"github.com/go-logr/logr"
@ -17,8 +18,8 @@ func Verify() AdmissionHandler {
return func(ctx context.Context, logger logr.Logger, request *admissionv1.AdmissionRequest, startTime time.Time) *admissionv1.AdmissionResponse {
return tracing.Span1(
ctx,
"admission_webhook_operations",
"verify",
"webhooks/handlers",
fmt.Sprintf("VERIFY %s %s", request.Operation, request.Kind),
func(ctx context.Context, span trace.Span) *admissionv1.AdmissionResponse {
if request.Name != "kyverno-health" || request.Namespace != config.KyvernoNamespace() {
return admissionutils.ResponseSuccess()
@ -31,6 +32,7 @@ func Verify() AdmissionHandler {
}
return admissionutils.MutationResponse(bytes)
},
trace.WithAttributes(admissionRequestAttributes(request)...),
)
}
}