diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index e3ddf418..8878b72e 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -4,6 +4,7 @@ on: workflow_dispatch: jobs: + lint: name: Lint runs-on: ubuntu-latest @@ -11,25 +12,22 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 2 - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: - go-version: '1.21' - - name: Install dependencies - run: go mod download - - name: Install GolangCI Lint - run: curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.55.2 - + go-version-file: 'go.mod' - name: golangci-lint - run: golangci-lint run --timeout=30m --max-same-issues=0 --out-format=github-actions + uses: golangci/golangci-lint-action@v4 + with: + version: v1.55.2 test: name: Unit Test runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v4 + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 with: - go-version: '1.21' + go-version-file: 'go.mod' - name: Install dependencies run: go mod download - name: Run Tests @@ -41,9 +39,9 @@ jobs: steps: - uses: actions/checkout@v4 - run: git fetch --no-tags --no-recurse-submodules --depth=1 origin master:master - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: - go-version: '1.21' + go-version-file: 'go.mod' - name: Install dependencies run: go mod download - name: Install Swagger @@ -69,6 +67,6 @@ jobs: name: Build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Build docker image run: docker build . diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 00000000..810cb8c3 --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,15 @@ +run: + timeout: 30m + +linters: + enable: + - errcheck + - gosimple + - govet + - ineffassign + - staticcheck + - unused + - zerologlint + +issues: + max-same-issues: 0 \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 873710b2..d39f06fd 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -22,7 +22,9 @@ "REQUIRE_APP_CONFIGURATION_ITEM": "true", "REQUIRE_APP_AD_GROUPS": "true", "RADIX_ENVIRONMENT":"qa", - "RADIX_APP":"radix-api" + "RADIX_APP":"radix-api", + "LOG_LEVEL":"info", + "LOG_PRETTY":"true" }, "args": [ "--useOutClusterClient=false" diff --git a/Dockerfile b/Dockerfile index cfe8ee7e..1ddc94dd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.21-alpine3.18 as builder +FROM golang:1.21-alpine3.19 as builder ENV GO111MODULE=on RUN apk update && \ diff --git a/Makefile b/Makefile index 1c827334..874e53a4 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,8 @@ mocks: bootstrap mockgen -source ./api/utils/tlsvalidation/interface.go -destination ./api/utils/tlsvalidation/mock/tls_secret_validator_mock.go -package mock mockgen -source ./api/utils/jobscheduler/interface.go -destination ./api/utils/jobscheduler/mock/job_scheduler_factory_mock.go -package mock mockgen -source ./api/events/event_handler.go -destination ./api/events/mock/event_handler_mock.go -package mock + mockgen -source ./api/environmentvariables/env_vars_handler.go -destination ./api/environmentvariables/env_vars_handler_mock.go -package environmentvariables + mockgen -source ./api/environmentvariables/env_vars_handler_factory.go -destination ./api/environmentvariables/env_vars_handler_factory_mock.go -package environmentvariables .PHONY: test test: diff --git a/api/applications/applications_handler.go b/api/applications/applications_handler.go index 3ad062bd..8e187621 100644 --- a/api/applications/applications_handler.go +++ b/api/applications/applications_handler.go @@ -29,7 +29,7 @@ import ( v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" "github.com/equinor/radix-operator/pkg/apis/radixvalidators" operatorUtils "github.com/equinor/radix-operator/pkg/apis/utils" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" authorizationapi "k8s.io/api/authorization/v1" rbacv1 "k8s.io/api/rbac/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -144,7 +144,8 @@ func (ah *ApplicationHandler) RegisterApplication(ctx context.Context, applicati } if len(application.SharedSecret) == 0 { application.SharedSecret = radixutils.RandString(20) - log.Debugf("There is no Shared Secret specified for the registering application - a random Shared Secret has been generated") + + log.Ctx(ctx).Debug().Msg("There is no Shared Secret specified for the registering application - a random Shared Secret has been generated") } radixRegistration, err := applicationModels.NewApplicationRegistrationBuilder(). @@ -431,7 +432,7 @@ func (ah *ApplicationHandler) TriggerPipelinePromote(ctx context.Context, appNam return nil, radixhttp.ValidationError("Radix Application Pipeline", "Deployment name, from environment and to environment are required for \"promote\" pipeline") } - log.Infof("Creating promote pipeline job for %s using deployment %s from environment %s into environment %s", appName, deploymentName, fromEnvironment, toEnvironment) + log.Ctx(ctx).Info().Msgf("Creating promote pipeline job for %s using deployment %s from environment %s into environment %s", appName, deploymentName, fromEnvironment, toEnvironment) jobParameters := pipelineParameters.MapPipelineParametersPromoteToJobParameter() @@ -470,7 +471,7 @@ func (ah *ApplicationHandler) TriggerPipelineDeploy(ctx context.Context, appName return nil, radixhttp.ValidationError("Radix Application Pipeline", "To environment is required for \"deploy\" pipeline") } - log.Infof("Creating deploy pipeline job for %s into environment %s", appName, toEnvironment) + log.Ctx(ctx).Info().Msgf("Creating deploy pipeline job for %s into environment %s", appName, toEnvironment) pipeline, err := jobPipeline.GetPipelineFromName("deploy") if err != nil { @@ -502,7 +503,7 @@ func (ah *ApplicationHandler) triggerPipelineBuildOrBuildDeploy(ctx context.Cont return nil, applicationModels.AppNameAndBranchAreRequiredForStartingPipeline() } - log.Infof("Creating build pipeline job for %s on branch %s for commit %s", appName, branch, commitID) + log.Ctx(ctx).Info().Msgf("Creating build pipeline job for %s on branch %s for commit %s", appName, branch, commitID) radixRegistration, err := ah.getUserAccount().RadixClient.RadixV1().RadixRegistrations().Get(ctx, appName, metav1.GetOptions{}) if err != nil { @@ -528,7 +529,7 @@ func (ah *ApplicationHandler) triggerPipelineBuildOrBuildDeploy(ctx context.Cont return nil, err } - log.Infof("Creating build pipeline job for %s on branch %s for commit %s", appName, branch, commitID) + log.Ctx(ctx).Info().Msgf("Creating build pipeline job for %s on branch %s for commit %s", appName, branch, commitID) jobSummary, err := ah.jobHandler.HandleStartPipelineJob(ctx, appName, pipeline, jobParameters) if err != nil { @@ -631,7 +632,7 @@ func (ah *ApplicationHandler) RegenerateDeployKey(ctx context.Context, appName s return false, err }) if errors.Is(err, context.DeadlineExceeded) { - log.Warnf("context deadline exceeded while waiting for new deploy key secret to be created for application %s", appName) + log.Ctx(ctx).Warn().Msgf("context deadline exceeded while waiting for new deploy key secret to be created for application %s", appName) return nil } return err @@ -708,7 +709,7 @@ func (ah *ApplicationHandler) validateUserIsMemberOfAdGroups(ctx context.Context defer func() { err = deleteRole(context.Background(), ah.accounts.ServiceAccount.Client, ah.namespace, role.GetName()) if err != nil { - log.Warnf("Failed to delete role %s: %v", role.GetName(), err) + log.Ctx(ctx).Warn().Msgf("Failed to delete role %s: %v", role.GetName(), err) } }() roleBinding, err := createRoleBindingForRole(ctx, ah.accounts.ServiceAccount.Client, ah.namespace, role, name, adGroups, labels) @@ -718,7 +719,7 @@ func (ah *ApplicationHandler) validateUserIsMemberOfAdGroups(ctx context.Context defer func() { err = deleteRoleBinding(context.Background(), ah.accounts.ServiceAccount.Client, ah.namespace, roleBinding.GetName()) if err != nil { - log.Warnf("Failed to delete role binding %s: %v", roleBinding.GetName(), err) + log.Ctx(ctx).Warn().Msgf("Failed to delete role binding %s: %v", roleBinding.GetName(), err) } }() diff --git a/api/applications/validate_handler.go b/api/applications/validate_handler.go index a749647e..be15fc65 100644 --- a/api/applications/validate_handler.go +++ b/api/applications/validate_handler.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/equinor/radix-operator/pkg/apis/utils" + "github.com/rs/zerolog/log" "github.com/equinor/radix-api/models" radixhttp "github.com/equinor/radix-common/net/http" @@ -16,7 +17,6 @@ import ( v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" "github.com/equinor/radix-operator/pkg/apis/utils/git" operatornumbers "github.com/equinor/radix-operator/pkg/apis/utils/numbers" - log "github.com/sirupsen/logrus" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -71,7 +71,8 @@ func verifyDeployKey(ctx context.Context, client kubernetes.Interface, rr *v1.Ra } return radixhttp.ValidationError("Radix Registration", message) default: - log.Debugf("Ongoing - build docker image") + + log.Ctx(ctx).Debug().Msg("Ongoing - build docker image") } } diff --git a/api/environments/component_handler.go b/api/environments/component_handler.go index 032179e2..6a309007 100644 --- a/api/environments/component_handler.go +++ b/api/environments/component_handler.go @@ -13,7 +13,7 @@ import ( v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" operatorUtils "github.com/equinor/radix-operator/pkg/apis/utils" jsonPatch "github.com/evanphx/json-patch/v5" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -27,7 +27,8 @@ const ( // StopComponent Stops a component func (eh EnvironmentHandler) StopComponent(ctx context.Context, appName, envName, componentName string, ignoreComponentStatusError bool) error { - log.Infof("Stopping component %s, %s", componentName, appName) + + log.Ctx(ctx).Info().Msgf("Stopping component %s, %s", componentName, appName) updater, err := eh.getRadixCommonComponentUpdater(ctx, appName, envName, componentName) if err != nil { return err @@ -47,7 +48,7 @@ func (eh EnvironmentHandler) StopComponent(ctx context.Context, appName, envName // StartComponent Starts a component func (eh EnvironmentHandler) StartComponent(ctx context.Context, appName, envName, componentName string, ignoreComponentStatusError bool) error { - log.Infof("Starting component %s, %s", componentName, appName) + log.Ctx(ctx).Info().Msgf("Starting component %s, %s", componentName, appName) updater, err := eh.getRadixCommonComponentUpdater(ctx, appName, envName, componentName) if err != nil { return err @@ -67,7 +68,7 @@ func (eh EnvironmentHandler) StartComponent(ctx context.Context, appName, envNam // RestartComponent Restarts a component func (eh EnvironmentHandler) RestartComponent(ctx context.Context, appName, envName, componentName string, ignoreComponentStatusError bool) error { - log.Infof("Restarting component %s, %s", componentName, appName) + log.Ctx(ctx).Info().Msgf("Restarting component %s, %s", componentName, appName) updater, err := eh.getRadixCommonComponentUpdater(ctx, appName, envName, componentName) if err != nil { return err @@ -84,7 +85,7 @@ func (eh EnvironmentHandler) RestartComponent(ctx context.Context, appName, envN // RestartComponentAuxiliaryResource Restarts a component's auxiliary resource func (eh EnvironmentHandler) RestartComponentAuxiliaryResource(ctx context.Context, appName, envName, componentName, auxType string) error { - log.Infof("Restarting auxiliary resource %s for component %s, %s", auxType, componentName, appName) + log.Ctx(ctx).Info().Msgf("Restarting auxiliary resource %s for component %s, %s", auxType, componentName, appName) deploySummary, err := eh.deployHandler.GetLatestDeploymentForApplicationEnvironment(ctx, appName, envName) if err != nil { @@ -136,7 +137,7 @@ func (eh EnvironmentHandler) ScaleComponent(ctx context.Context, appName, envNam if replicas > maxScaleReplicas { return environmentModels.CannotScaleComponentToMoreThanMaxReplicas(appName, envName, componentName, maxScaleReplicas) } - log.Infof("Scaling component %s, %s to %d replicas", componentName, appName, replicas) + log.Ctx(ctx).Info().Msgf("Scaling component %s, %s to %d replicas", componentName, appName, replicas) updater, err := eh.getRadixCommonComponentUpdater(ctx, appName, envName, componentName) if err != nil { return err @@ -184,9 +185,8 @@ func getReplicasForComponentInEnvironment(environmentConfig v1.RadixCommonEnviro func (eh EnvironmentHandler) patch(ctx context.Context, namespace, name string, oldJSON, newJSON []byte) error { patchBytes, err := jsonPatch.CreateMergePatch(oldJSON, newJSON) - if err != nil { - log.Fatalln(err) + return err } if patchBytes != nil { diff --git a/api/environments/environment_controller.go b/api/environments/environment_controller.go index 083b9f69..4f00bf08 100644 --- a/api/environments/environment_controller.go +++ b/api/environments/environment_controller.go @@ -14,7 +14,6 @@ import ( "github.com/equinor/radix-api/models" "github.com/equinor/radix-operator/pkg/apis/defaults" "github.com/gorilla/mux" - log "github.com/sirupsen/logrus" ) const rootPath = "/applications/{appName}" @@ -272,7 +271,7 @@ func (c *environmentController) GetApplicationEnvironmentDeployments(accounts mo c.ErrorResponse(w, r, err) } - c.JSONResponse(w,r, appEnvironmentDeployments) + c.JSONResponse(w, r, appEnvironmentDeployments) } // CreateEnvironment Creates a new environment @@ -1106,7 +1105,7 @@ func (c *environmentController) GetPodLog(accounts models.Accounts, w http.Respo fileName := fmt.Sprintf("%s.log", time.Now().Format("20060102150405")) c.ReaderFileResponse(w, r, logs, fileName, "text/plain; charset=utf-8") } else { - c.ReaderResponse(w, r, logs, "text/plain; charset=utf-8") + c.ReaderResponse(w, r, logs, "text/plain; charset=utf-8") } } @@ -1187,14 +1186,14 @@ func (c *environmentController) GetScheduledJobLog(accounts models.Accounts, w h c.ErrorResponse(w, r, err) return } - defer func() {_ = logs.Close()}() + defer func() { _ = logs.Close() }() if asFile { fileName := fmt.Sprintf("%s.log", time.Now().Format("20060102150405")) c.ReaderFileResponse(w, r, logs, fileName, "text/plain; charset=utf-8") } else { - c.ReaderResponse(w, r, logs, "text/plain; charset=utf-8") + c.ReaderResponse(w, r, logs, "text/plain; charset=utf-8") } } @@ -2095,7 +2094,7 @@ func (c *environmentController) GetOAuthAuxiliaryResourcePodLog(accounts models. c.ErrorResponse(w, r, err) return } - defer func() {_ = logs.Close()}() + defer func() { _ = logs.Close() }() if asFile { fileName := fmt.Sprintf("%s.log", time.Now().Format("20060102150405")) @@ -2161,7 +2160,8 @@ func (c *environmentController) GetJobPayload(accounts models.Accounts, w http.R return } - c.ReaderResponse(w, r, payload, "text/plain; charset=utf-8")} + c.ReaderResponse(w, r, payload, "text/plain; charset=utf-8") +} // ScaleComponent Scale component replicas func (c *environmentController) ScaleComponent(accounts models.Accounts, w http.ResponseWriter, r *http.Request) { @@ -2216,7 +2216,6 @@ func (c *environmentController) ScaleComponent(accounts models.Accounts, w http. componentName := mux.Vars(r)["componentName"] replicas, err := strconv.Atoi(mux.Vars(r)["replicas"]) if err != nil { - log.Error(err) c.ErrorResponse(w, r, fmt.Errorf("invalid new desired number of replicas argument")) return } diff --git a/api/environments/environment_handler.go b/api/environments/environment_handler.go index 9202fc41..2c57d006 100644 --- a/api/environments/environment_handler.go +++ b/api/environments/environment_handler.go @@ -26,7 +26,7 @@ import ( v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" k8sObjectUtils "github.com/equinor/radix-operator/pkg/apis/utils" radixclient "github.com/equinor/radix-operator/pkg/client/clientset/versioned" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" @@ -326,7 +326,7 @@ func (eh EnvironmentHandler) StopEnvironment(ctx context.Context, appName, envNa return err } - log.Infof("Stopping components in environment %s, %s", envName, appName) + log.Ctx(ctx).Info().Msgf("Stopping components in environment %s, %s", envName, appName) for _, deployComponent := range radixDeployment.Spec.Components { err := eh.StopComponent(ctx, appName, envName, deployComponent.GetName(), true) if err != nil { @@ -343,7 +343,7 @@ func (eh EnvironmentHandler) StartEnvironment(ctx context.Context, appName, envN return err } - log.Infof("Starting components in environment %s, %s", envName, appName) + log.Ctx(ctx).Info().Msgf("Starting components in environment %s, %s", envName, appName) for _, deployComponent := range radixDeployment.Spec.Components { err := eh.StartComponent(ctx, appName, envName, deployComponent.GetName(), true) if err != nil { @@ -360,7 +360,7 @@ func (eh EnvironmentHandler) RestartEnvironment(ctx context.Context, appName, en return err } - log.Infof("Restarting components in environment %s, %s", envName, appName) + log.Ctx(ctx).Info().Msgf("Restarting components in environment %s, %s", envName, appName) for _, deployComponent := range radixDeployment.Spec.Components { err := eh.RestartComponent(ctx, appName, envName, deployComponent.GetName(), true) if err != nil { @@ -376,7 +376,7 @@ func (eh EnvironmentHandler) StopApplication(ctx context.Context, appName string if err != nil { return err } - log.Infof("Stopping components in the application %s", appName) + log.Ctx(ctx).Info().Msgf("Stopping components in the application %s", appName) for _, environmentName := range environmentNames { err := eh.StopEnvironment(ctx, appName, environmentName) if err != nil { @@ -392,7 +392,7 @@ func (eh EnvironmentHandler) StartApplication(ctx context.Context, appName strin if err != nil { return err } - log.Infof("Starting components in the application %s", appName) + log.Ctx(ctx).Info().Msgf("Starting components in the application %s", appName) for _, environmentName := range environmentNames { err := eh.StartEnvironment(ctx, appName, environmentName) if err != nil { @@ -408,7 +408,7 @@ func (eh EnvironmentHandler) RestartApplication(ctx context.Context, appName str if err != nil { return err } - log.Infof("Restarting components in the application %s", appName) + log.Ctx(ctx).Info().Msgf("Restarting components in the application %s", appName) for _, environmentName := range environmentNames { err := eh.RestartEnvironment(ctx, appName, environmentName) if err != nil { diff --git a/api/environmentvariables/env_vars_controller.go b/api/environmentvariables/env_vars_controller.go index 26724564..aa50bb91 100644 --- a/api/environmentvariables/env_vars_controller.go +++ b/api/environmentvariables/env_vars_controller.go @@ -7,7 +7,7 @@ import ( envvarsmodels "github.com/equinor/radix-api/api/environmentvariables/models" "github.com/equinor/radix-api/models" "github.com/gorilla/mux" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) const rootPath = "/applications/{appName}" @@ -90,7 +90,7 @@ func (controller *envVarsController) GetComponentEnvVars(accounts models.Account appName, envName, componentName := mux.Vars(r)["appName"], mux.Vars(r)["envName"], mux.Vars(r)["componentName"] eh := controller.handlerFactory.createHandler(accounts) - envVars, err := eh.GetComponentEnvVars(appName, envName, componentName) + envVars, err := eh.GetComponentEnvVars(r.Context(), appName, envName, componentName) if err != nil { controller.ErrorResponse(w, r, err) @@ -162,11 +162,11 @@ func (controller *envVarsController) ChangeEnvVar(accounts models.Accounts, w ht return } - log.Debugf("Update %d environment variables for app: %s, env: %s, component: %s", len(envVarParameters), appName, envName, componentName) + log.Ctx(r.Context()).Debug().Msgf("Update %d environment variables for app: %s, env: %s, component: %s", len(envVarParameters), appName, envName, componentName) envVarsHandler := controller.handlerFactory.createHandler(accounts) - err := envVarsHandler.ChangeEnvVar(appName, envName, componentName, envVarParameters) + err := envVarsHandler.ChangeEnvVar(r.Context(), appName, envName, componentName, envVarParameters) if err != nil { controller.ErrorResponse(w, r, err) return diff --git a/api/environmentvariables/env_vars_controller_test.go b/api/environmentvariables/env_vars_controller_test.go index 89fea9bd..130e52cc 100644 --- a/api/environmentvariables/env_vars_controller_test.go +++ b/api/environmentvariables/env_vars_controller_test.go @@ -69,7 +69,7 @@ func Test_GetComponentEnvVars(t *testing.T) { commonTestUtils, controllerTestUtils, _, _, _, handler := setupTestWithMockHandler(t, mockCtrl) _, err := setupDeployment(commonTestUtils, appName, environmentName, componentName, nil) require.NoError(t, err) - handler.EXPECT().GetComponentEnvVars(appName, environmentName, componentName). + handler.EXPECT().GetComponentEnvVars(gomock.Any(), appName, environmentName, componentName). Return([]envvarsmodels.EnvVar{ { Name: "VAR1", @@ -112,7 +112,7 @@ func Test_GetComponentEnvVars(t *testing.T) { commonTestUtils, controllerTestUtils, _, _, _, handler := setupTestWithMockHandler(t, mockCtrl) _, err := setupDeployment(commonTestUtils, appName, environmentName, componentName, nil) require.NoError(t, err) - handler.EXPECT().GetComponentEnvVars(appName, environmentName, componentName). + handler.EXPECT().GetComponentEnvVars(gomock.Any(), appName, environmentName, componentName). Return(nil, fmt.Errorf("some-err")) responseChannel := controllerTestUtils.ExecuteRequest("GET", url) @@ -154,7 +154,7 @@ func Test_ChangeEnvVar(t *testing.T) { _, err := setupDeployment(commonTestUtils, appName, environmentName, componentName, nil) require.NoError(t, err) - handler.EXPECT().ChangeEnvVar(appName, environmentName, componentName, envVarsParams). + handler.EXPECT().ChangeEnvVar(gomock.Any(), appName, environmentName, componentName, envVarsParams). Return(nil) responseChannel := controllerTestUtils.ExecuteRequestWithParameters("PATCH", url, envVarsParams) @@ -172,7 +172,7 @@ func Test_ChangeEnvVar(t *testing.T) { _, err := setupDeployment(commonTestUtils, appName, environmentName, componentName, nil) require.NoError(t, err) - handler.EXPECT().ChangeEnvVar(appName, environmentName, componentName, envVarsParams). + handler.EXPECT().ChangeEnvVar(gomock.Any(), appName, environmentName, componentName, envVarsParams). Return(fmt.Errorf("some-err")) responseChannel := controllerTestUtils.ExecuteRequestWithParameters("PATCH", url, envVarsParams) diff --git a/api/environmentvariables/env_vars_handler.go b/api/environmentvariables/env_vars_handler.go index 7902ac69..6d48c215 100644 --- a/api/environmentvariables/env_vars_handler.go +++ b/api/environmentvariables/env_vars_handler.go @@ -1,24 +1,25 @@ package environmentvariables import ( + "context" "fmt" "sort" "strings" "github.com/equinor/radix-operator/pkg/apis/deployment" + "github.com/rs/zerolog/log" envvarsmodels "github.com/equinor/radix-api/api/environmentvariables/models" "github.com/equinor/radix-api/models" "github.com/equinor/radix-operator/pkg/apis/kube" v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" crdUtils "github.com/equinor/radix-operator/pkg/apis/utils" - log "github.com/sirupsen/logrus" "k8s.io/client-go/kubernetes" ) type EnvVarsHandler interface { - GetComponentEnvVars(appName string, envName string, componentName string) ([]envvarsmodels.EnvVar, error) - ChangeEnvVar(appName, envName, componentName string, envVarsParams []envvarsmodels.EnvVarParameter) error + GetComponentEnvVars(ctx context.Context, appName string, envName string, componentName string) ([]envvarsmodels.EnvVar, error) + ChangeEnvVar(ctx context.Context, appName, envName, componentName string, envVarsParams []envvarsmodels.EnvVarParameter) error } // EnvVarsHandlerOptions defines a configuration function @@ -52,8 +53,8 @@ func Init(opts ...EnvVarsHandlerOptions) EnvVarsHandler { return &eh } -//GetComponentEnvVars Get environment variables with metadata for the component -func (eh *envVarsHandler) GetComponentEnvVars(appName string, envName string, componentName string) ([]envvarsmodels.EnvVar, error) { +// GetComponentEnvVars Get environment variables with metadata for the component +func (eh *envVarsHandler) GetComponentEnvVars(ctx context.Context, appName string, envName string, componentName string) ([]envvarsmodels.EnvVar, error) { namespace := crdUtils.GetEnvironmentNamespace(appName, envName) rd, err := eh.kubeUtil.GetActiveDeployment(namespace) if err != nil { @@ -118,8 +119,8 @@ func appendSecretRefsKeysToMap(namesMap map[string]interface{}, secretRefs v1.Ra return namesMap } -//ChangeEnvVar Change environment variables -func (eh *envVarsHandler) ChangeEnvVar(appName, envName, componentName string, envVarsParams []envvarsmodels.EnvVarParameter) error { +// ChangeEnvVar Change environment variables +func (eh *envVarsHandler) ChangeEnvVar(ctx context.Context, appName, envName, componentName string, envVarsParams []envvarsmodels.EnvVarParameter) error { namespace := crdUtils.GetEnvironmentNamespace(appName, envName) currentEnvVarsConfigMap, envVarsMetadataConfigMap, envVarsMetadataMap, err := eh.kubeUtil.GetEnvVarsConfigMapAndMetadataMap(namespace, componentName) desiredEnvVarsConfigMap := currentEnvVarsConfigMap.DeepCopy() @@ -133,7 +134,8 @@ func (eh *envVarsHandler) ChangeEnvVar(appName, envName, componentName string, e } currentEnvVarValue, foundEnvVar := desiredEnvVarsConfigMap.Data[envVarParam.Name] if !foundEnvVar { - log.Infof("Not found changing variable %s", envVarParam.Name) + + log.Ctx(ctx).Info().Msgf("Not found changing variable %s", envVarParam.Name) hasChanges = true delete(envVarsMetadataMap, envVarParam.Name) continue diff --git a/api/environmentvariables/env_vars_handler_mock.go b/api/environmentvariables/env_vars_handler_mock.go index e4a8fd96..06b4da43 100644 --- a/api/environmentvariables/env_vars_handler_mock.go +++ b/api/environmentvariables/env_vars_handler_mock.go @@ -5,6 +5,7 @@ package environmentvariables import ( + context "context" reflect "reflect" models "github.com/equinor/radix-api/api/environmentvariables/models" @@ -35,30 +36,30 @@ func (m *MockEnvVarsHandler) EXPECT() *MockEnvVarsHandlerMockRecorder { } // ChangeEnvVar mocks base method. -func (m *MockEnvVarsHandler) ChangeEnvVar(appName, envName, componentName string, envVarsParams []models.EnvVarParameter) error { +func (m *MockEnvVarsHandler) ChangeEnvVar(ctx context.Context, appName, envName, componentName string, envVarsParams []models.EnvVarParameter) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ChangeEnvVar", appName, envName, componentName, envVarsParams) + ret := m.ctrl.Call(m, "ChangeEnvVar", ctx, appName, envName, componentName, envVarsParams) ret0, _ := ret[0].(error) return ret0 } // ChangeEnvVar indicates an expected call of ChangeEnvVar. -func (mr *MockEnvVarsHandlerMockRecorder) ChangeEnvVar(appName, envName, componentName, envVarsParams interface{}) *gomock.Call { +func (mr *MockEnvVarsHandlerMockRecorder) ChangeEnvVar(ctx, appName, envName, componentName, envVarsParams interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeEnvVar", reflect.TypeOf((*MockEnvVarsHandler)(nil).ChangeEnvVar), appName, envName, componentName, envVarsParams) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChangeEnvVar", reflect.TypeOf((*MockEnvVarsHandler)(nil).ChangeEnvVar), ctx, appName, envName, componentName, envVarsParams) } // GetComponentEnvVars mocks base method. -func (m *MockEnvVarsHandler) GetComponentEnvVars(appName, envName, componentName string) ([]models.EnvVar, error) { +func (m *MockEnvVarsHandler) GetComponentEnvVars(ctx context.Context, appName, envName, componentName string) ([]models.EnvVar, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetComponentEnvVars", appName, envName, componentName) + ret := m.ctrl.Call(m, "GetComponentEnvVars", ctx, appName, envName, componentName) ret0, _ := ret[0].([]models.EnvVar) ret1, _ := ret[1].(error) return ret0, ret1 } // GetComponentEnvVars indicates an expected call of GetComponentEnvVars. -func (mr *MockEnvVarsHandlerMockRecorder) GetComponentEnvVars(appName, envName, componentName interface{}) *gomock.Call { +func (mr *MockEnvVarsHandlerMockRecorder) GetComponentEnvVars(ctx, appName, envName, componentName interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetComponentEnvVars", reflect.TypeOf((*MockEnvVarsHandler)(nil).GetComponentEnvVars), appName, envName, componentName) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetComponentEnvVars", reflect.TypeOf((*MockEnvVarsHandler)(nil).GetComponentEnvVars), ctx, appName, envName, componentName) } diff --git a/api/environmentvariables/env_vars_handler_test.go b/api/environmentvariables/env_vars_handler_test.go index c4305aed..a571471d 100644 --- a/api/environmentvariables/env_vars_handler_test.go +++ b/api/environmentvariables/env_vars_handler_test.go @@ -1,6 +1,7 @@ package environmentvariables import ( + "context" "testing" envvarsmodels "github.com/equinor/radix-api/api/environmentvariables/models" @@ -38,7 +39,7 @@ func Test_GetEnvVars(t *testing.T) { _, err = kubeUtil.GetConfigMap(namespace, kube.GetEnvVarsMetadataConfigMapName(componentName)) require.NoError(t, err) - envVars, err := handler.GetComponentEnvVars(appName, environmentName, componentName) + envVars, err := handler.GetComponentEnvVars(context.Background(), appName, environmentName, componentName) assert.NoError(t, err) assert.NotEmpty(t, envVars) @@ -87,11 +88,11 @@ func Test_ChangeGetEnvVars(t *testing.T) { Value: "new-val3", }, } - err = handler.ChangeEnvVar(appName, environmentName, componentName, params) + err = handler.ChangeEnvVar(context.Background(), appName, environmentName, componentName, params) assert.NoError(t, err) - envVars, err := handler.GetComponentEnvVars(appName, environmentName, componentName) + envVars, err := handler.GetComponentEnvVars(context.Background(), appName, environmentName, componentName) assert.NoError(t, err) assert.NotEmpty(t, envVars) assert.Len(t, envVars, 3) @@ -136,11 +137,11 @@ func Test_ChangeGetEnvVars(t *testing.T) { Value: "new-val2", }, } - err = handler.ChangeEnvVar(appName, environmentName, componentName, params) + err = handler.ChangeEnvVar(context.Background(), appName, environmentName, componentName, params) require.NoError(t, err) - envVars, err := handler.GetComponentEnvVars(appName, environmentName, componentName) + envVars, err := handler.GetComponentEnvVars(context.Background(), appName, environmentName, componentName) assert.NoError(t, err) assert.NotEmpty(t, envVars) assert.Len(t, envVars, 2) diff --git a/api/jobs/log_handler.go b/api/jobs/log_handler.go index 69362563..bc547ca9 100644 --- a/api/jobs/log_handler.go +++ b/api/jobs/log_handler.go @@ -12,7 +12,7 @@ import ( "github.com/equinor/radix-api/api/utils/tekton" radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" crdUtils "github.com/equinor/radix-operator/pkg/apis/utils" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" pipelinev1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -29,9 +29,6 @@ func (jh JobHandler) GetTektonPipelineRunTaskStepLogs(ctx context.Context, appNa return nil, err } podHandler := pods.Init(jh.userAccount.Client) - if err != nil { - return nil, err - } return podHandler.HandleGetAppPodLog(ctx, appName, podName, containerName, sinceTime, logLines) } @@ -70,7 +67,7 @@ func (jh JobHandler) GetPipelineJobStepLogs(ctx context.Context, appName, jobNam podHandler := pods.Init(jh.userAccount.Client) logReader, err := podHandler.HandleGetAppPodLog(ctx, appName, stepPodName, stepName, sinceTime, logLines) if err != nil { - log.Warnf("Failed to get build logs. %v", err) + log.Ctx(ctx).Warn().Msgf("Failed to get build logs. %v", err) return nil, err } return logReader, nil diff --git a/api/jobs/manage_job_handler.go b/api/jobs/manage_job_handler.go index 4aa2be58..3c0c6a9e 100644 --- a/api/jobs/manage_job_handler.go +++ b/api/jobs/manage_job_handler.go @@ -8,7 +8,7 @@ import ( "github.com/equinor/radix-api/api/kubequery" "github.com/equinor/radix-common/utils/slice" radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -20,7 +20,7 @@ var ( // StopJob Stops an application job func (jh JobHandler) StopJob(ctx context.Context, appName, jobName string) error { - log.Infof("Stopping the job: %s, %s", jobName, appName) + log.Ctx(ctx).Info().Msgf("Stopping the job: %s, %s", jobName, appName) radixJob, err := jh.getPipelineJobByName(ctx, appName, jobName) if err != nil { return err @@ -43,7 +43,7 @@ func (jh JobHandler) StopJob(ctx context.Context, appName, jobName string) error // RerunJob Reruns the pipeline job as a copy func (jh JobHandler) RerunJob(ctx context.Context, appName, jobName string) error { - log.Infof("Rerunning the job %s in the application %s", jobName, appName) + log.Ctx(ctx).Info().Msgf("Rerunning the job %s in the application %s", jobName, appName) radixJob, err := jh.getPipelineJobByName(ctx, appName, jobName) if err != nil { return err @@ -52,7 +52,7 @@ func (jh JobHandler) RerunJob(ctx context.Context, appName, jobName string) erro return jobModels.JobHasInvalidConditionToRerunError(appName, jobName, radixJob.Status.Condition) } - copiedRadixJob := jh.buildPipelineJobToRerunFrom(radixJob) + copiedRadixJob := jh.buildPipelineJobToRerunFrom(ctx, radixJob) _, err = jh.createPipelineJob(ctx, appName, copiedRadixJob) if err != nil { return fmt.Errorf("failed to create a job %s to rerun: %v", radixJob.GetName(), err) @@ -61,7 +61,7 @@ func (jh JobHandler) RerunJob(ctx context.Context, appName, jobName string) erro return nil } -func (jh JobHandler) buildPipelineJobToRerunFrom(radixJob *radixv1.RadixJob) *radixv1.RadixJob { +func (jh JobHandler) buildPipelineJobToRerunFrom(ctx context.Context, radixJob *radixv1.RadixJob) *radixv1.RadixJob { rerunJobName, imageTag := getUniqueJobName(workerImage) rerunRadixJob := radixv1.RadixJob{ ObjectMeta: metav1.ObjectMeta{ @@ -81,7 +81,7 @@ func (jh JobHandler) buildPipelineJobToRerunFrom(radixJob *radixv1.RadixJob) *ra rerunRadixJob.Spec.Stop = false triggeredBy, err := jh.getTriggeredBy("") if err != nil { - log.Warnf("failed to get triggeredBy: %v", err) + log.Ctx(ctx).Warn().Msgf("failed to get triggeredBy: %v", err) } rerunRadixJob.Spec.TriggeredBy = triggeredBy return &rerunRadixJob diff --git a/api/jobs/start_job_handler.go b/api/jobs/start_job_handler.go index c01e415d..a41ea7e4 100644 --- a/api/jobs/start_job_handler.go +++ b/api/jobs/start_job_handler.go @@ -9,6 +9,7 @@ import ( "github.com/equinor/radix-operator/pkg/apis/defaults" "github.com/equinor/radix-operator/pkg/apis/radixvalidators" + "github.com/rs/zerolog/log" jobModels "github.com/equinor/radix-api/api/jobs/models" "github.com/equinor/radix-api/api/metrics" @@ -17,7 +18,6 @@ import ( pipelineJob "github.com/equinor/radix-operator/pkg/apis/pipeline" v1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" k8sObjectUtils "github.com/equinor/radix-operator/pkg/apis/utils" - log "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -35,12 +35,12 @@ func (jh JobHandler) HandleStartPipelineJob(ctx context.Context, appName string, return nil, err } - job := jh.buildPipelineJob(appName, radixRegistration.Spec.CloneURL, radixConfigFullName, pipeline, jobParameters) + job := jh.buildPipelineJob(ctx, appName, radixRegistration.Spec.CloneURL, radixConfigFullName, pipeline, jobParameters) return jh.createPipelineJob(ctx, appName, job) } func (jh JobHandler) createPipelineJob(ctx context.Context, appName string, job *v1.RadixJob) (*jobModels.JobSummary, error) { - log.Infof("Starting job: %s, %s", job.GetName(), workerImage) + log.Ctx(ctx).Info().Msgf("Starting job: %s, %s", job.GetName(), workerImage) appNamespace := k8sObjectUtils.GetAppNamespace(appName) job, err := jh.userAccount.RadixClient.RadixV1().RadixJobs(appNamespace).Create(ctx, job, metav1.CreateOptions{}) if err != nil { @@ -49,7 +49,7 @@ func (jh JobHandler) createPipelineJob(ctx context.Context, appName string, job metrics.AddJobTriggered(appName, string(job.Spec.PipeLineType)) - log.Infof("Started job: %s, %s", job.GetName(), workerImage) + log.Ctx(ctx).Info().Msgf("Started job: %s, %s", job.GetName(), workerImage) return jobModels.GetSummaryFromRadixJob(job), nil } @@ -63,7 +63,7 @@ func getRadixConfigFullName(radixRegistration *v1.RadixRegistration) (string, er return radixRegistration.Spec.RadixConfigFullName, nil } -func (jh JobHandler) buildPipelineJob(appName, cloneURL, radixConfigFullName string, pipeline *pipelineJob.Definition, jobSpec *jobModels.JobParameters) *v1.RadixJob { +func (jh JobHandler) buildPipelineJob(ctx context.Context, appName, cloneURL, radixConfigFullName string, pipeline *pipelineJob.Definition, jobSpec *jobModels.JobParameters) *v1.RadixJob { jobName, imageTag := getUniqueJobName(workerImage) if len(jobSpec.ImageTag) > 0 { imageTag = jobSpec.ImageTag @@ -75,7 +75,7 @@ func (jh JobHandler) buildPipelineJob(appName, cloneURL, radixConfigFullName str triggeredBy, err := jh.getTriggeredBy(jobSpec.TriggeredBy) if err != nil { - log.Warnf("failed to get triggeredBy: %v", err) + log.Ctx(ctx).Warn().Msgf("failed to get triggeredBy: %v", err) } switch pipeline.Type { @@ -116,8 +116,8 @@ func (jh JobHandler) buildPipelineJob(appName, cloneURL, radixConfigFullName str AppName: appName, CloneURL: cloneURL, PipeLineType: pipeline.Type, - PipelineImage: getPipelineTag(), - TektonImage: getTektonTag(), + PipelineImage: getPipelineTag(ctx), + TektonImage: getTektonTag(ctx), Build: buildSpec, Promote: promoteSpec, Deploy: deploySpec, @@ -140,24 +140,24 @@ func (jh JobHandler) getTriggeredBy(triggeredBy string) (string, error) { return triggeredBy, nil } -func getPipelineTag() string { +func getPipelineTag(ctx context.Context) string { pipelineTag := os.Getenv(pipelineTagEnvironmentVariable) if pipelineTag == "" { - log.Warning("No pipeline image tag defined. Using latest") + log.Ctx(ctx).Warn().Msg("No pipeline image tag defined. Using latest") pipelineTag = "latest" } else { - log.Infof("Using %s pipeline image tag", pipelineTag) + log.Ctx(ctx).Info().Msgf("Using %s pipeline image tag", pipelineTag) } return pipelineTag } -func getTektonTag() string { +func getTektonTag(ctx context.Context) string { tektonTag := os.Getenv(tektonTagEnvironmentVariable) if tektonTag == "" { - log.Warning("No tekton image tag defined. Using release-latest") + log.Ctx(ctx).Warn().Msg("No tekton image tag defined. Using release-latest") tektonTag = "release-latest" } else { - log.Infof("Using %s as tekton image tag", tektonTag) + log.Ctx(ctx).Info().Msgf("Using %s as tekton image tag", tektonTag) } return tektonTag } diff --git a/api/kubequery/radixdnsalias.go b/api/kubequery/radixdnsalias.go index 0568cfde..6aba928b 100644 --- a/api/kubequery/radixdnsalias.go +++ b/api/kubequery/radixdnsalias.go @@ -8,7 +8,7 @@ import ( "github.com/equinor/radix-common/utils/slice" radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" radixclient "github.com/equinor/radix-operator/pkg/client/clientset/versioned" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -22,7 +22,7 @@ func GetDNSAliases(ctx context.Context, client radixclient.Interface, radixAppli radixDNSAlias, err := client.RadixV1().RadixDNSAliases().Get(ctx, dnsAlias.Alias, metav1.GetOptions{}) if err != nil { if !errors.IsNotFound(err) && !errors.IsForbidden(err) { - log.Errorf("failed to get DNS alias %s: %v", dnsAlias.Alias, err) + log.Ctx(ctx).Error().Err(err).Msgf("failed to get DNS alias %s", dnsAlias.Alias) } return acc } diff --git a/api/models/component.go b/api/models/component.go index a2b98cda..4cd53c64 100644 --- a/api/models/component.go +++ b/api/models/component.go @@ -13,7 +13,7 @@ import ( operatordeployment "github.com/equinor/radix-operator/pkg/apis/deployment" radixv1 "github.com/equinor/radix-operator/pkg/apis/radix/v1" operatorutils "github.com/equinor/radix-operator/pkg/apis/utils" - "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" appsv1 "k8s.io/api/apps/v1" autoscalingv2 "k8s.io/api/autoscaling/v2" corev1 "k8s.io/api/core/v1" @@ -146,7 +146,8 @@ func getComponentStatus(component radixv1.RadixCommonDeployComponent, ra *radixv restartedTime, err := commonutils.ParseTimestamp(restarted) if err != nil { // TODO: How should we handle invalid value for restarted time? - logrus.Warnf("unable to parse restarted time %v: %v", restarted, err) + + log.Logger.Warn().Err(err).Msgf("unable to parse restarted time %v", restarted) return deploymentModels.ConsistentComponent } reconciledTime := rd.Status.Reconciled diff --git a/api/router/middleware.go b/api/router/middleware.go new file mode 100644 index 00000000..71b510bc --- /dev/null +++ b/api/router/middleware.go @@ -0,0 +1,62 @@ +package router + +import ( + "context" + "net" + "net/http" + + "github.com/felixge/httpsnoop" + "github.com/rs/xid" + "github.com/rs/zerolog" + "github.com/urfave/negroni/v3" +) + +func zerologRequestLogger() negroni.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + m := httpsnoop.CaptureMetrics(next, w, r) + + logger := zerolog.Ctx(r.Context()) + + var ev *zerolog.Event + switch { + case m.Code >= 400 && m.Code <= 499: + ev = logger.Warn() //nolint:zerologlint // Msg for ev is called later + case m.Code >= 500: + ev = logger.Error() //nolint:zerologlint // Msg for ev is called later + default: + ev = logger.Info() //nolint:zerologlint // Msg for ev is called later + } + + remoteIp, _, _ := net.SplitHostPort(r.RemoteAddr) + ev. + Str("remote_addr", remoteIp). + Str("referer", r.Referer()). + Str("method", r.Method). + Str("path", r.URL.Path). + Str("query", r.URL.RawQuery). + Int("status", m.Code). + Int64("body_size", m.Written). + Int64("elapsed_ms", m.Duration.Milliseconds()). + Str("user_agent", r.UserAgent()). + Msg(http.StatusText(m.Code)) + } +} + +type setZerologLoggerFn func(context.Context) zerolog.Logger + +// zerologLoggerWithRequestId returns a zerolog logger with a request_id field with a new GUID +func zerologLoggerWithRequestId(ctx context.Context) zerolog.Logger { + return zerolog.Ctx(ctx).With().Str("request_id", xid.New().String()).Logger() +} + +// setZerologLogger attaches the zerolog logger returned from each loggerFns function to a shallow copy of the request context +// The logger can then be accessed in a controller method by calling zerolog.Ctx(ctx) +func setZerologLogger(loggerFns ...setZerologLoggerFn) negroni.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + for _, loggerFn := range loggerFns { + logger := loggerFn(r.Context()) + r = r.WithContext(logger.WithContext(r.Context())) + } + next.ServeHTTP(w, r) + } +} diff --git a/api/router/server.go b/api/router/server.go index 094da3c6..712c68cd 100644 --- a/api/router/server.go +++ b/api/router/server.go @@ -12,6 +12,7 @@ import ( "github.com/gorilla/mux" "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/rs/cors" + "github.com/rs/zerolog/log" "github.com/urfave/negroni/v3" ) @@ -52,8 +53,11 @@ func NewServer(clusterName string, kubeUtil utils.KubeUtil, controllers ...model rec := negroni.NewRecovery() rec.PrintStack = false + n := negroni.New( rec, + setZerologLogger(zerologLoggerWithRequestId), + zerologRequestLogger(), ) n.UseHandler(serveMux) @@ -92,11 +96,14 @@ func getCORSHandler(clusterName string, handler http.Handler, useOutClusterClien if !useOutClusterClient { // debugging mode corsOptions.Debug = true + corsLogger := log.Logger.With().Str("pkg", "cors-middleware").Logger() + corsOptions.Logger = &corsLogger // necessary header to allow ajax requests directly from radix-web-console app in browser corsOptions.AllowedHeaders = append(corsOptions.AllowedHeaders, "X-Requested-With") } c := cors.New(corsOptions) + return c.Handler(handler) } diff --git a/api/test/utils.go b/api/test/utils.go index ef72c9f9..13b94548 100644 --- a/api/test/utils.go +++ b/api/test/utils.go @@ -7,6 +7,7 @@ import ( "net/http" "net/http/httptest" + "github.com/rs/zerolog/log" tektonclient "github.com/tektoncd/pipeline/pkg/client/clientset/versioned" secretsstorevclient "sigs.k8s.io/secrets-store-csi-driver/pkg/client/clientset/versioned" @@ -16,7 +17,6 @@ import ( radixmodels "github.com/equinor/radix-common/models" radixhttp "github.com/equinor/radix-common/net/http" radixclient "github.com/equinor/radix-operator/pkg/client/clientset/versioned" - log "github.com/sirupsen/logrus" kubernetes "k8s.io/client-go/kubernetes" ) @@ -94,7 +94,7 @@ func GetErrorResponse(response *httptest.ResponseRecorder) (*radixhttp.Error, er errorResponse := &radixhttp.Error{} err := GetResponseBody(response, errorResponse) if err != nil { - log.Infof("%v", err) + log.Logger.Error().Err(err).Msg("Failed to get response body") return nil, err } diff --git a/api/utils/kubernetes.go b/api/utils/kubernetes.go index a89d7a4c..1ca95aae 100644 --- a/api/utils/kubernetes.go +++ b/api/utils/kubernetes.go @@ -10,7 +10,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "github.com/prometheus/client_golang/prometheus/promhttp" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" tektonclient "github.com/tektoncd/pipeline/pkg/client/clientset/versioned" "k8s.io/client-go/kubernetes" restclient "k8s.io/client-go/rest" @@ -116,7 +116,7 @@ func getInClusterClientConfig(options []RestClientConfigOption) *restclient.Conf if err != nil { config, err = restclient.InClusterConfig() if err != nil { - log.Fatalf("getClusterConfig InClusterConfig: %v", err) + log.Fatal().Err(err).Msg("getClusterConfig InClusterConfig") } } @@ -137,22 +137,22 @@ func addCommonConfigs(config *restclient.Config, options []RestClientConfigOptio func getKubernetesClientFromConfig(config *restclient.Config) (kubernetes.Interface, radixclient.Interface, secretproviderclient.Interface, tektonclient.Interface) { client, err := kubernetes.NewForConfig(config) if err != nil { - log.Fatalf("getClusterConfig k8s client: %v", err) + log.Fatal().Err(err).Msg("getClusterConfig k8s client") } radixClient, err := radixclient.NewForConfig(config) if err != nil { - log.Fatalf("getClusterConfig radix client: %v", err) + log.Fatal().Err(err).Msg("getClusterConfig radix client") } secretProviderClient, err := secretproviderclient.NewForConfig(config) if err != nil { - log.Fatalf("getClusterConfig secret provider client client: %v", err) + log.Fatal().Err(err).Msg("getClusterConfig secret provider client client") } tektonClient, err := tektonclient.NewForConfig(config) if err != nil { - log.Fatalf("getClusterConfig Tekton client client: %v", err) + log.Fatal().Err(err).Msg("getClusterConfig Tekton client client") } return client, radixClient, secretProviderClient, tektonClient } diff --git a/api/utils/radix_middleware.go b/api/utils/radix_middleware.go index 180f729d..2291f84b 100644 --- a/api/utils/radix_middleware.go +++ b/api/utils/radix_middleware.go @@ -8,7 +8,7 @@ import ( "github.com/equinor/radix-api/models" radixhttp "github.com/equinor/radix-common/net/http" "github.com/gorilla/mux" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -56,20 +56,23 @@ func (handler *RadixMiddleware) Handle(w http.ResponseWriter, r *http.Request) { } func (handler *RadixMiddleware) handleAuthorization(w http.ResponseWriter, r *http.Request) { + logger := log.Ctx(r.Context()) useOutClusterClient := handler.kubeUtil.IsUseOutClusterClient() token, err := getBearerTokenFromHeader(r, useOutClusterClient) if err != nil { + logger.Warn().Err(err).Msg("authorization error") if err = radixhttp.ErrorResponse(w, r, err); err != nil { - log.Errorf("handleAuthorization: failed to write error response: %v", err) + logger.Err(err).Msg("failed to write response") } return } impersonation, err := radixhttp.GetImpersonationFromHeader(r) if err != nil { + logger.Warn().Err(err).Msg("authorization error") if err = radixhttp.ErrorResponse(w, r, radixhttp.UnexpectedError("Problems impersonating", err)); err != nil { - log.Errorf("handleAuthorization: failed to write error response: %v", err) + logger.Err(err).Msg("failed to write response") } return } @@ -93,8 +96,9 @@ func (handler *RadixMiddleware) handleAuthorization(w http.ResponseWriter, r *ht // Check if registration of application exists for application-specific requests if appName, exists := mux.Vars(r)["appName"]; exists { if _, err := accounts.UserAccount.RadixClient.RadixV1().RadixRegistrations().Get(r.Context(), appName, metav1.GetOptions{}); err != nil { + logger.Warn().Err(err).Msg("authorization error") if err = radixhttp.ErrorResponse(w, r, err); err != nil { - log.Errorf("handleAuthorization: failed to write error response: %v", err) + logger.Err(err).Msg("failed to write response") } return } diff --git a/go.mod b/go.mod index f8c0c9f6..174428db 100644 --- a/go.mod +++ b/go.mod @@ -4,24 +4,25 @@ go 1.21 require ( github.com/cert-manager/cert-manager v1.14.2 - github.com/equinor/radix-common v1.8.0 - github.com/equinor/radix-job-scheduler v1.8.5 + github.com/equinor/radix-common v1.9.2 + github.com/equinor/radix-job-scheduler v1.9.0 github.com/equinor/radix-operator v1.50.2 github.com/evanphx/json-patch/v5 v5.7.0 + github.com/felixge/httpsnoop v1.0.4 github.com/go-swagger/go-swagger v0.30.5 github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang/mock v1.6.0 - github.com/gorilla/handlers v1.5.2 github.com/gorilla/mux v1.8.1 github.com/marstr/guid v1.1.0 github.com/mitchellh/mapstructure v1.5.0 github.com/prometheus-operator/prometheus-operator/pkg/client v0.70.0 github.com/prometheus/client_golang v1.18.0 github.com/rs/cors v1.10.1 - github.com/sirupsen/logrus v1.9.3 + github.com/rs/xid v1.5.0 + github.com/rs/zerolog v1.32.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.18.2 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 github.com/tektoncd/pipeline v0.55.0 github.com/urfave/negroni/v3 v3.0.0 golang.org/x/sync v0.5.0 @@ -45,7 +46,6 @@ require ( github.com/elnormous/contenttype v1.0.4 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch v5.7.0+incompatible // indirect - github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect @@ -71,6 +71,8 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -86,6 +88,7 @@ require ( github.com/prometheus/statsd_exporter v0.22.7 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect diff --git a/go.sum b/go.sum index 9d0743dc..52e4f88b 100644 --- a/go.sum +++ b/go.sum @@ -54,15 +54,21 @@ 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/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= +github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= +github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cert-manager/cert-manager v1.14.2 h1:C/uci6yxiCRO04PWomBbSX+T4JT58FIIpDj5SZ6Ks6I= github.com/cert-manager/cert-manager v1.14.2/go.mod h1:pik7K6jXfgh++lfVJ/i1HzEnDluSUtTVLXSHikj8Lho= +github.com/cert-manager/cert-manager v1.14.2 h1:C/uci6yxiCRO04PWomBbSX+T4JT58FIIpDj5SZ6Ks6I= +github.com/cert-manager/cert-manager v1.14.2/go.mod h1:pik7K6jXfgh++lfVJ/i1HzEnDluSUtTVLXSHikj8Lho= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= +github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -70,6 +76,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cloudevents/sdk-go/v2 v2.14.0 h1:Nrob4FwVgi5L4tV9lhjzZcjYqFVyJzsA56CwPaPfv6s= github.com/cloudevents/sdk-go/v2 v2.14.0/go.mod h1:xDmKfzNjM8gBvjaF8ijFjM1VYOVUEeUfapHMUX1T5To= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -82,10 +89,10 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/equinor/radix-common v1.8.0 h1:4mMu36mvJi2QSPEiKOUUJG/Z5EUrPkf0/lRO1qzkt5c= -github.com/equinor/radix-common v1.8.0/go.mod h1:8wGBEAa6auVB3yQ5pImahQzrL3w1ZYTu6N7EXLpJKUk= -github.com/equinor/radix-job-scheduler v1.8.5 h1:ahw6FkFpPV167B1/w7/aQKpVMmU5Vc7UBO8411ZtYck= -github.com/equinor/radix-job-scheduler v1.8.5/go.mod h1:rNIQU1eCInLV8Yl+5SRITOUU52QwYioYrIGQcsDc3kg= +github.com/equinor/radix-common v1.9.2 h1:pOYN/mSAoPe6KO/Nvudfd5DUETbLv4nLTLzFPr62ADw= +github.com/equinor/radix-common v1.9.2/go.mod h1:ekn86U68NT4ccSdt3GT+ukpiclzfuhr96a7zBJKv/jw= +github.com/equinor/radix-job-scheduler v1.9.0 h1:ceq46IZPf0VfPjYr6XSRy8WPid8fn5JR0bMovD/dAJ8= +github.com/equinor/radix-job-scheduler v1.9.0/go.mod h1:8220ViUF4YLOvl2z+VJQnMOaZ6jhPMfHYWdIOuUGPdo= github.com/equinor/radix-operator v1.50.2 h1:xa5kPUN77QT6QJq9+DJzF/ic2c7AJcl4KKztky38sdc= github.com/equinor/radix-operator v1.50.2/go.mod h1:rl8Tbor0wvKfol67nd/p72MRh0iDTClGeQ2HcMRG/LQ= github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= @@ -98,7 +105,13 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= +github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= +github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -122,11 +135,20 @@ github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdX github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= github.com/go-openapi/swag v0.22.7 h1:JWrc1uc/P9cSomxfnsFSVWoE1FW6bNbrVPmpQYpCcR8= github.com/go-openapi/swag v0.22.7/go.mod h1:Gl91UqO+btAM0plGGxHqJcQZ1ZTy6jbmridBTsDy8A0= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= +github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-swagger/go-swagger v0.30.5 h1:SQ2+xSonWjjoEMOV5tcOnZJVlfyUfCBhGQGArS1b9+U= github.com/go-swagger/go-swagger v0.30.5/go.mod h1:cWUhSyCNqV7J1wkkxfr5QmbcnCewetCdvEXqgPvbc/Q= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -207,13 +229,13 @@ github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= -github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U= github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1/go.mod h1:YvJ2f6MplWDhfxiUC3KpyTy76kYUZA4W3pTv/wdKQ9Y= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -225,9 +247,13 @@ github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iP github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= +github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= +github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= @@ -244,6 +270,8 @@ github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dv github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= 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/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= +github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -254,12 +282,19 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= +github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/marstr/guid v1.1.0 h1:/M4H/1G4avsieL6BbUwCOBzulmoeKVP5ux/3mQNnbyI= github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg= github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= @@ -333,8 +368,14 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/rs/xid v1.5.0 h1:mKX4bl4iPYJtEIxp6CYiUuLQ/8DYMoz0PUdtGgMFRVc= +github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0= +github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss= github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= @@ -356,6 +397,8 @@ github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= +github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= @@ -368,13 +411,18 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/tektoncd/pipeline v0.55.0 h1:RUfqSC/J1dMrdfu1ThJreHojwGXcWc8P131el/c+c1c= github.com/tektoncd/pipeline v0.55.0/go.mod h1:fFbFAhyNwsPQpitrwhi+Wp0Xse2EkIE1LtGKC08rVqo= +github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= +github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= +github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/negroni/v3 v3.0.0 h1:Vo8CeZfu1lFR9gW8GnAb6dOGCJyijfil9j/jKKc/JhU= github.com/urfave/negroni/v3 v3.0.0/go.mod h1:jWvnX03kcSjDBl/ShB0iHvx5uOs7mAzZXW+JvJ5XYAs= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -400,6 +448,8 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8 go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= +golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -421,6 +471,8 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4= golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4= +golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -553,6 +605,9 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -690,6 +745,12 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1: google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0= google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU= +google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= +google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= +google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM= +google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -721,6 +782,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -765,6 +828,10 @@ k8s.io/kube-openapi v0.0.0-20240103051144-eec4567ac022 h1:avRdiaB03v88Mfvum2S3BB k8s.io/kube-openapi v0.0.0-20240103051144-eec4567ac022/go.mod h1:sIV51WBTkZrlGOJMCDZDA1IaPBUDTulPpD4y7oe038k= k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/kube-openapi v0.0.0-20240103051144-eec4567ac022 h1:avRdiaB03v88Mfvum2S3BBwkNuTlmuar4LlfO9Hajko= +k8s.io/kube-openapi v0.0.0-20240103051144-eec4567ac022/go.mod h1:sIV51WBTkZrlGOJMCDZDA1IaPBUDTulPpD4y7oe038k= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCfRziVtos3ofG/sQ= +k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= knative.dev/pkg v0.0.0-20231219072704-d513e487961e h1:br9VUyN8M4ZUaWsmKifLg5lIAy6JmNw2MdeHd6wgp9g= knative.dev/pkg v0.0.0-20231219072704-d513e487961e/go.mod h1:YWJGsIxySXQehfkslagVEpJJwHgSScUc21+KpEgBXcY= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= @@ -774,6 +841,8 @@ sigs.k8s.io/controller-runtime v0.16.3 h1:2TuvuokmfXvDUamSx1SuAOO3eTyye+47mJCigw sigs.k8s.io/controller-runtime v0.16.3/go.mod h1:j7bialYoSn142nv9sCOJmQgDXQXxnroFU4VnX/brVJ0= sigs.k8s.io/gateway-api v1.0.0 h1:iPTStSv41+d9p0xFydll6d7f7MOBGuqXM6p2/zVYMAs= sigs.k8s.io/gateway-api v1.0.0/go.mod h1:4cUgr0Lnp5FZ0Cdq8FdRwCvpiWws7LVhLHGIudLlf4c= +sigs.k8s.io/gateway-api v1.0.0 h1:iPTStSv41+d9p0xFydll6d7f7MOBGuqXM6p2/zVYMAs= +sigs.k8s.io/gateway-api v1.0.0/go.mod h1:4cUgr0Lnp5FZ0Cdq8FdRwCvpiWws7LVhLHGIudLlf4c= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/secrets-store-csi-driver v1.4.0 h1:R9JVcKOs11fEuiOLlH1BWMeyb6WYzvElRVkq1BWJkr4= diff --git a/main.go b/main.go index 2d4bfddd..21f42b08 100644 --- a/main.go +++ b/main.go @@ -2,21 +2,23 @@ package main import ( "fmt" + "io" "net/http" _ "net/http/pprof" "os" "strconv" + "time" "github.com/equinor/radix-api/api/secrets" "github.com/equinor/radix-api/api/utils/tlsvalidation" "github.com/equinor/radix-operator/pkg/apis/defaults" + "github.com/rs/zerolog" + "github.com/rs/zerolog/log" "github.com/equinor/radix-api/api/environmentvariables" "github.com/equinor/radix-api/api/buildstatus" - "github.com/gorilla/handlers" - log "github.com/sirupsen/logrus" "github.com/spf13/pflag" // Controllers @@ -36,18 +38,13 @@ import ( const ( logLevelEnvironmentVariable = "LOG_LEVEL" + logPrettyEnvironmentVariable = "LOG_PRETTY" useProfilerEnvironmentVariable = "USE_PROFILER" ) //go:generate swagger generate spec func main() { - switch os.Getenv(logLevelEnvironmentVariable) { - case "DEBUG": - log.SetLevel(log.DebugLevel) - default: - log.SetLevel(log.InfoLevel) - } - + initLogger() fs := initializeFlagSet() var ( @@ -63,35 +60,61 @@ func main() { controllers, err := getControllers() if err != nil { - log.Fatalf("Failed to get controllers: %v", err) + log.Fatal().Err(err).Msg("Failed to get controllers") } errs := make(chan error) + go func() { - log.Infof("Api is serving on port %s", *port) - err := http.ListenAndServe(fmt.Sprintf(":%s", *port), handlers.CombinedLoggingHandler(os.Stdout, router.NewServer(clusterName, utils.NewKubeUtil(*useOutClusterClient), controllers...))) + log.Info().Msgf("Api is serving on port %s", *port) + err := http.ListenAndServe(fmt.Sprintf(":%s", *port), router.NewServer(clusterName, utils.NewKubeUtil(*useOutClusterClient), controllers...)) errs <- err }() if certPath != "" && keyPath != "" { go func() { - log.Infof("Api is serving on port %s", httpsPort) + log.Info().Msgf("Api is serving on port %s", httpsPort) err := http.ListenAndServeTLS(fmt.Sprintf(":%s", httpsPort), certPath, keyPath, router.NewServer(clusterName, utils.NewKubeUtil(*useOutClusterClient), controllers...)) errs <- err }() } else { - log.Info("Https support disabled - Env variable server_cert_path and server_key_path is empty.") + log.Info().Msg("Https support disabled - Env variable server_cert_path and server_key_path is empty.") } if useProfiler, _ := strconv.ParseBool(os.Getenv(useProfilerEnvironmentVariable)); useProfiler { go func() { - log.Infof("Profiler endpoint is serving on port 7070") + log.Info().Msgf("Profiler endpoint is serving on port 7070") errs <- http.ListenAndServe("localhost:7070", nil) }() } err = <-errs if err != nil { - log.Fatalf("Web api server crashed: %v", err) + log.Fatal().Err(err).Msg("Web api server crashed") + } +} + +func initLogger() { + logLevelStr := os.Getenv(logLevelEnvironmentVariable) + if len(logLevelStr) == 0 { + logLevelStr = zerolog.LevelInfoValue + } + + logLevel, err := zerolog.ParseLevel(logLevelStr) + if err != nil { + logLevel = zerolog.InfoLevel + log.Warn().Msgf("Invalid log level '%s', fallback to '%s'", logLevelStr, logLevel.String()) } + + logPretty, _ := strconv.ParseBool(os.Getenv(logPrettyEnvironmentVariable)) + + var logWriter io.Writer = os.Stderr + if logPretty { + logWriter = &zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.TimeOnly} + } + + logger := zerolog.New(logWriter).Level(logLevel).With().Timestamp().Logger() + + log.Logger = logger + zerolog.DefaultContextLogger = &logger } func getControllers() ([]models.Controller, error) { diff --git a/models/controller.go b/models/controller.go index 1d061343..3d2251f4 100644 --- a/models/controller.go +++ b/models/controller.go @@ -5,7 +5,7 @@ import ( "net/http" radixhttp "github.com/equinor/radix-common/net/http" - log "github.com/sirupsen/logrus" + "github.com/rs/zerolog/log" ) // RadixHandlerFunc Pattern for handler functions @@ -24,7 +24,7 @@ type DefaultController struct { func (c *DefaultController) ErrorResponse(w http.ResponseWriter, r *http.Request, err error) { err = radixhttp.ErrorResponse(w, r, err) if err != nil { - log.Errorf("%s %s: failed to write response: %v", r.Method, r.URL.Path, err) + log.Ctx(r.Context()).Err(err).Msg("failed to write response") } } @@ -32,32 +32,32 @@ func (c *DefaultController) ErrorResponse(w http.ResponseWriter, r *http.Request func (c *DefaultController) JSONResponse(w http.ResponseWriter, r *http.Request, result interface{}) { err := radixhttp.JSONResponse(w, r, result) if err != nil { - log.Errorf("%s %s: failed to write response: %v",r.Method, r.URL.Path, err) + log.Ctx(r.Context()).Err(err).Msg("failed to write response") } } - // ReaderFileResponse writes the content from the reader to the response, // and sets Content-Disposition=attachment; filename= -func (c *DefaultController) ReaderFileResponse(w http.ResponseWriter, r *http.Request, reader io.Reader, fileName, contentType string) { +func (c *DefaultController) ReaderFileResponse(w http.ResponseWriter, r *http.Request, reader io.Reader, fileName, contentType string) { err := radixhttp.ReaderFileResponse(w, reader, fileName, contentType) if err != nil { - log.Errorf("%s %s: failed to write response: %v", r.Method, r.URL.Path, err) + log.Ctx(r.Context()).Err(err).Msg("failed to write response") } } + // ReaderResponse writes the content from the reader to the response, -func (c *DefaultController) ReaderResponse(w http.ResponseWriter, r *http.Request, reader io.Reader, contentType string) { +func (c *DefaultController) ReaderResponse(w http.ResponseWriter, r *http.Request, reader io.Reader, contentType string) { err := radixhttp.ReaderResponse(w, reader, contentType) if err != nil { - log.Errorf("%s %s: failed to write reader to response: %v", r.Method, r.URL.Path, err) + log.Ctx(r.Context()).Err(err).Msg("failed to write response") } } // ByteArrayResponse Used for response data. I.e. image -func (c *DefaultController) ByteArrayResponse(w http.ResponseWriter, r *http.Request, contentType string, result []byte) { +func (c *DefaultController) ByteArrayResponse(w http.ResponseWriter, r *http.Request, contentType string, result []byte) { err := radixhttp.ByteArrayResponse(w, r, contentType, result) if err != nil { - log.Errorf("%s %s: failed to write ByteArray response: %v", r.Method, r.URL.Path, err) + log.Ctx(r.Context()).Err(err).Msg("failed to write response") } } diff --git a/radixconfig.yaml b/radixconfig.yaml index f758cea0..aa12af4e 100644 --- a/radixconfig.yaml +++ b/radixconfig.yaml @@ -22,6 +22,8 @@ spec: REQUIRE_APP_CONFIGURATION_ITEM: "true" REQUIRE_APP_AD_GROUPS: "true" USE_PROFILER: "false" + LOG_LEVEL: info + LOG_PRETTY: "false" environmentConfig: - environment: qa runAsNonRoot: true