diff --git a/Gopkg.lock b/Gopkg.lock index 6057f6111b4..b91e28d31d3 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -791,6 +791,7 @@ input-imports = [ "github.com/coreos/prometheus-operator/pkg/client/monitoring/v1", "github.com/ghodss/yaml", + "github.com/go-logr/logr", "github.com/markbates/inflect", "github.com/prometheus/client_golang/prometheus", "github.com/prometheus/client_golang/prometheus/promhttp", diff --git a/commands/operator-sdk/cmd/add/api.go b/commands/operator-sdk/cmd/add/api.go index f5f0db379d4..b19d63e6758 100644 --- a/commands/operator-sdk/cmd/add/api.go +++ b/commands/operator-sdk/cmd/add/api.go @@ -15,13 +15,12 @@ package add import ( - "log" - "github.com/operator-framework/operator-sdk/commands/operator-sdk/cmd/generate" "github.com/operator-framework/operator-sdk/internal/util/projutil" "github.com/operator-framework/operator-sdk/pkg/scaffold" "github.com/operator-framework/operator-sdk/pkg/scaffold/input" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -68,6 +67,9 @@ func apiRun(cmd *cobra.Command, args []string) { // Create and validate new resource projutil.MustInProjectRoot() + + log.Infof("Generating api version %s for kind %s.", apiVersion, kind) + r, err := scaffold.NewResource(apiVersion, kind) if err != nil { log.Fatal(err) @@ -95,9 +97,11 @@ func apiRun(cmd *cobra.Command, args []string) { // update deploy/role.yaml for the given resource r. if err := scaffold.UpdateRoleForResource(r, absProjectPath); err != nil { - log.Fatalf("failed to update the RBAC manifest for the resource (%v, %v): %v", r.APIVersion, r.Kind, err) + log.Fatalf("failed to update the RBAC manifest for the resource (%v, %v): (%v)", r.APIVersion, r.Kind, err) } // Run k8s codegen for deepcopy generate.K8sCodegen() + + log.Info("Api generation complete.") } diff --git a/commands/operator-sdk/cmd/add/controller.go b/commands/operator-sdk/cmd/add/controller.go index bc1a3351d8e..3da37038e83 100644 --- a/commands/operator-sdk/cmd/add/controller.go +++ b/commands/operator-sdk/cmd/add/controller.go @@ -15,12 +15,11 @@ package add import ( - "log" - "github.com/operator-framework/operator-sdk/internal/util/projutil" "github.com/operator-framework/operator-sdk/pkg/scaffold" "github.com/operator-framework/operator-sdk/pkg/scaffold/input" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -61,6 +60,9 @@ func controllerRun(cmd *cobra.Command, args []string) { projutil.MustGoProjectCmd(cmd) projutil.MustInProjectRoot() + + log.Infof("Generating controller version %s for kind %s.", apiVersion, kind) + // Create and validate new resource r, err := scaffold.NewResource(apiVersion, kind) if err != nil { @@ -80,4 +82,6 @@ func controllerRun(cmd *cobra.Command, args []string) { if err != nil { log.Fatalf("add scaffold failed: (%v)", err) } + + log.Info("Controller generation complete.") } diff --git a/commands/operator-sdk/cmd/add/crd.go b/commands/operator-sdk/cmd/add/crd.go index e6980bae40d..617d6612ca0 100644 --- a/commands/operator-sdk/cmd/add/crd.go +++ b/commands/operator-sdk/cmd/add/crd.go @@ -15,8 +15,6 @@ package add import ( - "fmt" - "log" "os" "path/filepath" "strings" @@ -25,6 +23,7 @@ import ( "github.com/operator-framework/operator-sdk/pkg/scaffold" "github.com/operator-framework/operator-sdk/pkg/scaffold/input" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -60,27 +59,29 @@ func crdFunc(cmd *cobra.Command, args []string) { verifyCrdFlags() verifyCrdDeployPath() - fmt.Fprintln(os.Stdout, "Generating custom resource definition (CRD) file") + log.Infof("Generating Custom Resource Definition (CRD) version %s for kind %s.", apiVersion, kind) // generate CR/CRD file resource, err := scaffold.NewResource(apiVersion, kind) if err != nil { - log.Fatalf("%v", err) + log.Fatal(err) } + s := scaffold.Scaffold{} err = s.Execute(cfg, &scaffold.Crd{Resource: resource}, &scaffold.Cr{Resource: resource}, ) - if err != nil { log.Fatalf("add scaffold failed: (%v)", err) } // update deploy/role.yaml for the given resource r. if err := scaffold.UpdateRoleForResource(resource, cfg.AbsProjectPath); err != nil { - log.Fatalf("failed to update the RBAC manifest for the resource (%v, %v): %v", resource.APIVersion, resource.Kind, err) + log.Fatalf("failed to update the RBAC manifest for the resource (%v, %v): (%v)", resource.APIVersion, resource.Kind, err) } + + log.Info("CRD generation complete.") } func verifyCrdFlags() { @@ -103,7 +104,7 @@ func verifyCrdFlags() { func verifyCrdDeployPath() { wd, err := os.Getwd() if err != nil { - log.Fatalf("failed to determine the full path of the current directory: %v", err) + log.Fatalf("failed to determine the full path of the current directory: (%v)", err) } // check if the deploy sub-directory exist _, err = os.Stat(filepath.Join(wd, scaffold.DeployDir)) diff --git a/commands/operator-sdk/cmd/build.go b/commands/operator-sdk/cmd/build.go index cd638291fcf..d7c4d6de445 100644 --- a/commands/operator-sdk/cmd/build.go +++ b/commands/operator-sdk/cmd/build.go @@ -19,7 +19,6 @@ import ( "errors" "fmt" "io/ioutil" - "log" "os" "os/exec" "path/filepath" @@ -30,6 +29,7 @@ import ( "github.com/operator-framework/operator-sdk/pkg/test" "github.com/ghodss/yaml" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -78,11 +78,11 @@ func verifyDeploymentImage(yamlFile []byte, imageName string) error { yamlMap := make(map[string]interface{}) err := yaml.Unmarshal(yamlSpec, &yamlMap) if err != nil { - log.Fatal("Could not unmarshal yaml namespaced spec") + log.Fatalf("could not unmarshal yaml namespaced spec: (%v)", err) } kind, ok := yamlMap["kind"].(string) if !ok { - log.Fatal("Yaml manifest file contains a 'kind' field that is not a string") + log.Fatal("yaml manifest file contains a 'kind' field that is not a string") } if kind == "Deployment" { // this is ugly and hacky; we should probably make this cleaner @@ -122,13 +122,13 @@ func verifyDeploymentImage(yamlFile []byte, imageName string) error { func verifyTestManifest(image string) { namespacedBytes, err := ioutil.ReadFile(namespacedManBuild) if err != nil { - log.Fatalf("could not read namespaced manifest: %v", err) + log.Fatalf("could not read namespaced manifest: (%v)", err) } err = verifyDeploymentImage(namespacedBytes, image) // the error from verifyDeploymentImage is just a warning, not fatal error if err != nil { - fmt.Printf("%v\n", err) + log.Warn(err) } } @@ -141,7 +141,7 @@ func buildFunc(cmd *cobra.Command, args []string) { goBuildEnv := append(os.Environ(), "GOOS=linux", "GOARCH=amd64", "CGO_ENABLED=0") wd, err := os.Getwd() if err != nil { - log.Fatalf("could not identify current working directory: %v", err) + log.Fatalf("could not identify current working directory: (%v)", err) } // Don't need to build go code if Ansible Operator @@ -154,7 +154,7 @@ func buildFunc(cmd *cobra.Command, args []string) { buildCmd.Stderr = os.Stderr err = buildCmd.Run() if err != nil { - log.Fatalf("failed to build operator binary: %v", err) + log.Fatalf("failed to build operator binary: (%v)", err) } } @@ -163,15 +163,18 @@ func buildFunc(cmd *cobra.Command, args []string) { if enableTests { baseImageName += "-intermediate" } + + log.Infof("Building Docker image %s", baseImageName) + dbcmd := exec.Command("docker", "build", ".", "-f", "build/Dockerfile", "-t", baseImageName) dbcmd.Stdout = os.Stdout dbcmd.Stderr = os.Stderr err = dbcmd.Run() if err != nil { if enableTests { - log.Fatalf("failed to build intermediate image for %s image: %v", image, err) + log.Fatalf("failed to output intermediate image %s: (%v)", image, err) } else { - log.Fatalf("failed to output build image %s: %v", image, err) + log.Fatalf("failed to output build image %s: (%v)", image, err) } } @@ -183,13 +186,15 @@ func buildFunc(cmd *cobra.Command, args []string) { buildTestCmd.Stderr = os.Stderr err = buildTestCmd.Run() if err != nil { - log.Fatalf("failed to build test binary: %v", err) + log.Fatalf("failed to build test binary: (%v)", err) } // if a user is using an older sdk repo as their library, make sure they have required build files testDockerfile := filepath.Join(scaffold.BuildTestDir, scaffold.DockerfileFile) _, err = os.Stat(testDockerfile) if err != nil && os.IsNotExist(err) { + log.Info("Generating build manifests for test-framework.") + absProjectPath := projutil.MustGetwd() cfg := &input.Config{ Repo: projutil.CheckAndGetProjectGoPkg(), @@ -204,20 +209,24 @@ func buildFunc(cmd *cobra.Command, args []string) { &scaffold.TestPod{Image: image, TestNamespaceEnv: test.TestNamespaceEnv}, ) if err != nil { - log.Fatalf("build scaffold failed: (%v)", err) + log.Fatalf("test-framework manifest scaffold failed: (%v)", err) } } + log.Infof("Building test Docker image %s", image) + testDbcmd := exec.Command("docker", "build", ".", "-f", testDockerfile, "-t", image, "--build-arg", "NAMESPACEDMAN="+namespacedManBuild, "--build-arg", "BASEIMAGE="+baseImageName) testDbcmd.Stdout = os.Stdout testDbcmd.Stderr = os.Stderr err = testDbcmd.Run() if err != nil { - log.Fatalf("failed to output build image %s: %v", image, err) + log.Fatalf("failed to output test image %s: (%v)", image, err) } // Check image name of deployments in namespaced manifest verifyTestManifest(image) } + + log.Info("Operator build complete.") } func mainExists() bool { diff --git a/commands/operator-sdk/cmd/generate/k8s.go b/commands/operator-sdk/cmd/generate/k8s.go index 51ae9112777..4b331bbc486 100644 --- a/commands/operator-sdk/cmd/generate/k8s.go +++ b/commands/operator-sdk/cmd/generate/k8s.go @@ -17,7 +17,6 @@ package generate import ( "fmt" "io/ioutil" - "log" "os" "os/exec" "path/filepath" @@ -25,6 +24,7 @@ import ( "github.com/operator-framework/operator-sdk/internal/util/projutil" "github.com/operator-framework/operator-sdk/pkg/scaffold" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -41,7 +41,7 @@ to comply with kube-API requirements. func k8sFunc(cmd *cobra.Command, args []string) { if len(args) != 0 { - log.Fatalf("k8s command doesn't accept any arguments.") + log.Fatal("k8s command doesn't accept any arguments") } // Only Go projects can generate k8s deepcopy code. @@ -62,10 +62,10 @@ func K8sCodegen() { log.Fatalf("failed to parse group versions: (%v)", err) } - fmt.Fprintf(os.Stdout, "Running code-generation for custom resource group versions: [%s]\n", groupVersions) + log.Infof("Running code-generation for Custom Resource group versions: [%s]\n", groupVersions) + // TODO: Replace generate-groups.sh by building the vendored generators(deepcopy, lister etc) // and running them directly - // TODO: remove dependency on boilerplate.go.txt genGroupsCmd := "vendor/k8s.io/code-generator/generate-groups.sh" args := []string{ "deepcopy", @@ -73,11 +73,15 @@ func K8sCodegen() { apisPkg, groupVersions, } - out, err := exec.Command(genGroupsCmd, args...).CombinedOutput() + cgCmd := exec.Command(genGroupsCmd, args...) + cgCmd.Stdout = os.Stdout + cgCmd.Stderr = os.Stderr + err = cgCmd.Run() if err != nil { log.Fatalf("failed to perform code-generation: (%v)", err) } - fmt.Fprintln(os.Stdout, string(out)) + + log.Info("Code-generation complete.") } // getGroupVersions parses the layout of pkg/apis to return the API groups and versions @@ -108,5 +112,9 @@ func parseGroupVersions() (string, error) { } } + if groupVersions == "" { + return "", fmt.Errorf("no groups or versions found in %s", scaffold.ApisDir) + } + return groupVersions, nil } diff --git a/commands/operator-sdk/cmd/new.go b/commands/operator-sdk/cmd/new.go index b699089d775..af0b775e24b 100644 --- a/commands/operator-sdk/cmd/new.go +++ b/commands/operator-sdk/cmd/new.go @@ -15,9 +15,7 @@ package cmd import ( - "fmt" "io/ioutil" - "log" "os" "os/exec" "path/filepath" @@ -28,6 +26,7 @@ import ( "github.com/operator-framework/operator-sdk/pkg/scaffold/ansible" "github.com/operator-framework/operator-sdk/pkg/scaffold/input" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -80,6 +79,8 @@ func newFunc(cmd *cobra.Command, args []string) { mustBeNewProject() verifyFlags() + log.Infof("Creating new %s operator '%s'.", strings.Title(operatorType), projectName) + switch operatorType { case projutil.OperatorTypeGo: doScaffold() @@ -88,6 +89,8 @@ func newFunc(cmd *cobra.Command, args []string) { doAnsibleScaffold() } initGit() + + log.Info("Project creation complete.") } func parse(args []string) { @@ -150,13 +153,13 @@ func doAnsibleScaffold() { resource, err := scaffold.NewResource(apiVersion, kind) if err != nil { - log.Fatal("Invalid apiVersion and kind.") + log.Fatalf("invalid apiVersion and kind: (%v)", err) } s := &scaffold.Scaffold{} tmpdir, err := ioutil.TempDir("", "osdk") if err != nil { - log.Fatal("unable to get temp directory") + log.Fatalf("unable to get temp directory: (%v)", err) } galaxyInit := &ansible.GalaxyInit{ @@ -190,32 +193,37 @@ func doAnsibleScaffold() { // Decide on playbook. if generatePlaybook { + log.Infof("Generating %s playbook.", strings.Title(operatorType)) + err := s.Execute(cfg, &ansible.Playbook{ Resource: *resource, }, ) if err != nil { - log.Fatalf("new scaffold failed: (%v)", err) + log.Fatalf("new playbook scaffold failed: (%v)", err) } } + log.Info("Running galaxy-init.") + // Run galaxy init. cmd := exec.Command(filepath.Join(galaxyInit.AbsProjectPath, galaxyInit.Path)) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Run() + // Delete Galxy INIT // Mac OS tmp directory is /var/folders/_c/..... this means we have to make sure that we get the top level directory to remove // everything. tmpDirectorySlice := strings.Split(os.TempDir(), "/") if err = os.RemoveAll(filepath.Join(galaxyInit.AbsProjectPath, tmpDirectorySlice[1])); err != nil { - log.Fatalf("failed to remove the galaxy init script") + log.Fatalf("failed to remove the galaxy init script: (%v)", err) } // update deploy/role.yaml for the given resource r. if err := scaffold.UpdateRoleForResource(resource, cfg.AbsProjectPath); err != nil { - log.Fatalf("failed to update the RBAC manifest for the resource (%v, %v): %v", resource.APIVersion, resource.Kind, err) + log.Fatalf("failed to update the RBAC manifest for the resource (%v, %v): (%v)", resource.APIVersion, resource.Kind, err) } } @@ -254,27 +262,27 @@ func execCmd(stdout *os.File, cmd string, args ...string) { dc.Stderr = os.Stderr err := dc.Run() if err != nil { - log.Fatalf("failed to exec %s %#v: %v", cmd, args, err) + log.Fatalf("failed to exec %s %#v: (%v)", cmd, args, err) } } func pullDep() { _, err := exec.LookPath(dep) if err != nil { - log.Fatalf("looking for dep in $PATH: %v", err) + log.Fatalf("looking for dep in $PATH: (%v)", err) } - fmt.Fprintln(os.Stdout, "Run dep ensure ...") + log.Info("Run dep ensure ...") execCmd(os.Stdout, dep, ensureCmd, "-v") - fmt.Fprintln(os.Stdout, "Run dep ensure done") + log.Info("Run dep ensure done") } func initGit() { if skipGit { return } - fmt.Fprintln(os.Stdout, "Run git init ...") + log.Info("Run git init ...") execCmd(os.Stdout, "git", "init") execCmd(os.Stdout, "git", "add", "--all") execCmd(os.Stdout, "git", "commit", "-q", "-m", "INITIAL COMMIT") - fmt.Fprintln(os.Stdout, "Run git init done") + log.Info("Run git init done") } diff --git a/commands/operator-sdk/cmd/test/cluster.go b/commands/operator-sdk/cmd/test/cluster.go index 8abebee850d..3728c03e456 100644 --- a/commands/operator-sdk/cmd/test/cluster.go +++ b/commands/operator-sdk/cmd/test/cluster.go @@ -24,6 +24,7 @@ import ( "github.com/operator-framework/operator-sdk/pkg/scaffold" "github.com/operator-framework/operator-sdk/pkg/test" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -62,6 +63,9 @@ func testClusterFunc(cmd *cobra.Command, args []string) error { if len(args) != 1 { return fmt.Errorf("operator-sdk test cluster requires exactly 1 argument") } + + log.Info("Testing operator in cluster.") + var pullPolicy v1.PullPolicy if strings.ToLower(tcConfig.imagePullPolicy) == "always" { pullPolicy = v1.PullAlways @@ -110,7 +114,7 @@ func testClusterFunc(cmd *cobra.Command, args []string) error { defer func() { err = kubeclient.CoreV1().Pods(tcConfig.namespace).Delete(testPod.Name, &metav1.DeleteOptions{}) if err != nil { - fmt.Printf("Warning: failed to delete test pod") + log.Warn("failed to delete test pod") } }() err = wait.Poll(time.Second*5, time.Second*time.Duration(tcConfig.pendingTimeout), func() (bool, error) { @@ -140,7 +144,7 @@ func testClusterFunc(cmd *cobra.Command, args []string) error { time.Sleep(time.Second * 5) continue } else if testPod.Status.Phase == v1.PodSucceeded { - fmt.Printf("Test Successfully Completed\n") + log.Info("Cluster test successfully completed.") return nil } else if testPod.Status.Phase == v1.PodFailed { req := kubeclient.CoreV1().Pods(tcConfig.namespace).GetLogs(testPod.Name, &v1.PodLogOptions{}) diff --git a/commands/operator-sdk/cmd/test/local.go b/commands/operator-sdk/cmd/test/local.go index 17a8b72a3c9..bbf3f5ed04f 100644 --- a/commands/operator-sdk/cmd/test/local.go +++ b/commands/operator-sdk/cmd/test/local.go @@ -17,7 +17,6 @@ package cmdtest import ( "fmt" "io/ioutil" - "log" "os" "os/exec" "path/filepath" @@ -28,6 +27,7 @@ import ( "github.com/operator-framework/operator-sdk/pkg/scaffold" "github.com/operator-framework/operator-sdk/pkg/test" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -60,32 +60,34 @@ func NewTestLocalCmd() *cobra.Command { func testLocalFunc(cmd *cobra.Command, args []string) { if len(args) != 1 { - log.Fatalf("operator-sdk test local requires exactly 1 argument") + log.Fatal("operator-sdk test local requires exactly 1 argument") } + + log.Info("Testing operator locally.") + // if no namespaced manifest path is given, combine deploy/service_account.yaml, deploy/role.yaml, deploy/role_binding.yaml and deploy/operator.yaml if tlConfig.namespacedManPath == "" { err := os.MkdirAll(deployTestDir, os.FileMode(fileutil.DefaultDirFileMode)) if err != nil { - log.Fatalf("could not create %s: %v", deployTestDir, err) + log.Fatalf("could not create %s: (%v)", deployTestDir, err) } tlConfig.namespacedManPath = filepath.Join(deployTestDir, "namespace-manifests.yaml") - saFile := filepath.Join(scaffold.DeployDir, scaffold.ServiceAccountYamlFile) - sa, err := ioutil.ReadFile(saFile) + sa, err := ioutil.ReadFile(filepath.Join(scaffold.DeployDir, scaffold.ServiceAccountYamlFile)) if err != nil { - log.Printf("WARN: could not find the manifest %s: %v", saFile, err) + log.Warnf("could not find the serviceaccount manifest: (%v)", err) } role, err := ioutil.ReadFile(filepath.Join(scaffold.DeployDir, scaffold.RoleYamlFile)) if err != nil { - log.Printf("WARN: could not find role manifest: %v", err) + log.Warnf("could not find role manifest: (%v)", err) } roleBinding, err := ioutil.ReadFile(filepath.Join(scaffold.DeployDir, scaffold.RoleBindingYamlFile)) if err != nil { - log.Printf("WARN: could not find role_binding manifest: %v", err) + log.Warnf("could not find role_binding manifest: (%v)", err) } operator, err := ioutil.ReadFile(filepath.Join(scaffold.DeployDir, scaffold.OperatorYamlFile)) if err != nil { - log.Fatalf("could not find operator manifest: %v", err) + log.Fatalf("could not find operator manifest: (%v)", err) } combined := []byte{} combined = combineManifests(combined, sa) @@ -94,31 +96,31 @@ func testLocalFunc(cmd *cobra.Command, args []string) { combined = append(combined, operator...) err = ioutil.WriteFile(tlConfig.namespacedManPath, combined, os.FileMode(fileutil.DefaultFileMode)) if err != nil { - log.Fatalf("could not create temporary namespaced manifest file: %v", err) + log.Fatalf("could not create temporary namespaced manifest file: (%v)", err) } defer func() { err := os.Remove(tlConfig.namespacedManPath) if err != nil { - log.Fatalf("could not delete temporary namespace manifest file") + log.Fatalf("could not delete temporary namespace manifest file: (%v)", err) } }() } if tlConfig.globalManPath == "" { err := os.MkdirAll(deployTestDir, os.FileMode(fileutil.DefaultDirFileMode)) if err != nil { - log.Fatalf("could not create %s: %v", deployTestDir, err) + log.Fatalf("could not create %s: (%v)", deployTestDir, err) } tlConfig.globalManPath = filepath.Join(deployTestDir, "global-manifests.yaml") files, err := ioutil.ReadDir(scaffold.CrdsDir) if err != nil { - log.Fatalf("could not read deploy directory: %v", err) + log.Fatalf("could not read deploy directory: (%v)", err) } var combined []byte for _, file := range files { if strings.HasSuffix(file.Name(), "crd.yaml") { fileBytes, err := ioutil.ReadFile(filepath.Join(scaffold.CrdsDir, file.Name())) if err != nil { - log.Fatalf("could not read file %s: %v", filepath.Join(scaffold.CrdsDir, file.Name()), err) + log.Fatalf("could not read file %s: (%v)", filepath.Join(scaffold.CrdsDir, file.Name()), err) } if combined == nil { combined = []byte{} @@ -130,12 +132,12 @@ func testLocalFunc(cmd *cobra.Command, args []string) { } err = ioutil.WriteFile(tlConfig.globalManPath, combined, os.FileMode(fileutil.DefaultFileMode)) if err != nil { - log.Fatalf("could not create temporary global manifest file: %v", err) + log.Fatalf("could not create temporary global manifest file: (%v)", err) } defer func() { err := os.Remove(tlConfig.globalManPath) if err != nil { - log.Fatalf("could not delete global namespace manifest file") + log.Fatalf("could not delete global manifest file: (%v)", err) } }() } @@ -159,8 +161,10 @@ func testLocalFunc(cmd *cobra.Command, args []string) { dc.Stderr = os.Stderr err := dc.Run() if err != nil { - log.Fatalf("failed to exec `go %s`: %v", strings.Join(testArgs, " "), err) + log.Fatalf("failed to exec `go %s`: (%v)", strings.Join(testArgs, " "), err) } + + log.Info("Local operator test successfully completed.") } // combineManifests combines a given manifest with a base manifest and adds yaml diff --git a/commands/operator-sdk/cmd/up/local.go b/commands/operator-sdk/cmd/up/local.go index 4aa910ed2a9..d5ad9389685 100644 --- a/commands/operator-sdk/cmd/up/local.go +++ b/commands/operator-sdk/cmd/up/local.go @@ -16,7 +16,6 @@ package up import ( "fmt" - "log" "os" "os/exec" "os/signal" @@ -35,10 +34,11 @@ import ( ansibleScaffold "github.com/operator-framework/operator-sdk/pkg/scaffold/ansible" sdkVersion "github.com/operator-framework/operator-sdk/version" - "github.com/sirupsen/logrus" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/controller-runtime/pkg/manager" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" ) func NewLocalCmd() *cobra.Command { @@ -73,6 +73,9 @@ const ( func upLocalFunc(cmd *cobra.Command, args []string) { mustKubeConfig() + + log.Info("Running the operator locally.") + switch projutil.GetOperatorType() { case projutil.OperatorTypeGo: projutil.MustInProjectRoot() @@ -90,14 +93,14 @@ func mustKubeConfig() { if len(kubeConfig) == 0 { usr, err := user.Current() if err != nil { - log.Fatalf("failed to determine user's home dir: %v", err) + log.Fatalf("failed to determine user's home dir: (%v)", err) } kubeConfig = filepath.Join(usr.HomeDir, defaultConfigPath) } _, err := os.Stat(kubeConfig) if err != nil && os.IsNotExist(err) { - log.Fatalf("failed to find the kubeconfig file (%v): %v", kubeConfig, err) + log.Fatalf("failed to find the kubeconfig file (%v): (%v)", kubeConfig, err) } } @@ -118,29 +121,33 @@ func upLocal() { <-c err := dc.Process.Kill() if err != nil { - log.Fatalf("failed to terminate the operator: %v", err) + log.Fatalf("failed to terminate the operator: (%v)", err) } os.Exit(0) }() dc.Stdout = os.Stdout dc.Stderr = os.Stderr - dc.Env = append(os.Environ(), fmt.Sprintf("%v=%v", k8sutil.KubeConfigEnvVar, kubeConfig), fmt.Sprintf("%v=%v", k8sutil.WatchNamespaceEnvVar, namespace)) + dc.Env = append(os.Environ(), fmt.Sprintf("%v=%v", k8sutil.KubeConfigEnvVar, kubeConfig)) + dc.Env = append(dc.Env, fmt.Sprintf("%v=%v", k8sutil.WatchNamespaceEnvVar, namespace)) err := dc.Run() if err != nil { - log.Fatalf("failed to run operator locally: %v", err) + log.Fatalf("failed to run operator locally: (%v)", err) } } func upLocalAnsible() { // Set the kubeconfig that the manager will be able to grab os.Setenv(k8sutil.KubeConfigEnvVar, kubeConfig) + + logf.SetLogger(logf.ZapLogger(false)) + mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{Namespace: namespace}) if err != nil { log.Fatal(err) } printVersion() - logrus.Infof("watching namespace: %s", namespace) + log.Infof("watching namespace: %s", namespace) done := make(chan error) // start the proxy @@ -150,7 +157,7 @@ func upLocalAnsible() { KubeConfig: mgr.GetConfig(), }) if err != nil { - logrus.Fatalf("error starting proxy: %v", err) + log.Fatalf("error starting proxy: (%v)", err) } // start the operator @@ -158,15 +165,14 @@ func upLocalAnsible() { // wait for either to finish err = <-done - if err == nil { - logrus.Info("Exiting") - } else { - logrus.Fatal(err.Error()) + if err != nil { + log.Fatal(err) } + log.Info("Exiting.") } func printVersion() { - logrus.Infof("Go Version: %s", runtime.Version()) - logrus.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) - logrus.Infof("operator-sdk Version: %v", sdkVersion.Version) + log.Infof("Go Version: %s", runtime.Version()) + log.Infof("Go OS/Arch: %s/%s", runtime.GOOS, runtime.GOARCH) + log.Infof("operator-sdk Version: %v", sdkVersion.Version) } diff --git a/commands/operator-sdk/main.go b/commands/operator-sdk/main.go index 0c282e01479..6f8f2135578 100644 --- a/commands/operator-sdk/main.go +++ b/commands/operator-sdk/main.go @@ -15,15 +15,12 @@ package main import ( - "fmt" - "os" - "github.com/operator-framework/operator-sdk/commands/operator-sdk/cmd" + log "github.com/sirupsen/logrus" ) func main() { if err := cmd.NewRootCmd().Execute(); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(-1) + log.Fatal(err) } } diff --git a/doc/dev/logging.md b/doc/dev/logging.md new file mode 100644 index 00000000000..054ba84011e --- /dev/null +++ b/doc/dev/logging.md @@ -0,0 +1,105 @@ +# Logging in operators + +Operator SDK-generated operators use the [`logr`][godoc_logr] interface to log. This log interface has several backends such as [`zap`][repo_zapr], which the SDK uses in generated code by default. [`logr.Logger`][godoc_logr_logger] exposes [structured logging][site_struct_logging] methods that help create machine-readable logs and adding a wealth of information to log records. + +## Setting the logger + +Operators set the logger for all operator logging in [`cmd/manager/main.go`][code_set_logger]: + +```Go +import ( + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" +) + +func main() { + logf.SetLogger(logf.ZapLogger(false)) + log := logf.Log.WithName("cmd") + + ... + + log.Info("Starting the Cmd.") + + ... +} +``` + +By using `controller-runtime/pkg/runtime/log`, your logger is propagated through `controller-runtime`. Any logs produced by `controller-runtime` code will be through your logger, and therefore have the same formatting and destination. + +In the above example, `logf.ZapLogger()` takes a boolean flag to set development parameters. Passing in `true` will set the logger to log in development mode; debug log statements will trigger, and error log statements will include stack traces. + +## Creating a structured log statement + +There are two ways to create structured logs with `logr`. You can create new loggers using `log.WithValues(keyValues)` that include `keyValues`, a list of key-value pair `interface{}`'s, in each log record. Alternatively you can include `keyValues` directly in a log statement, as all `logr` log statements take some message and `keyValues`. The signature of `logr.Error()` has an `error`-type parameter, which can be `nil`. + +An example from [`memcached_controller.go`][code_memcached_controller]: + +```Go +package memcached + +import ( + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" +) + +// Set a global logger for the memcached package. Each log record produced +// by this logger will have an identifier containing "controller_memcached". +// These names are hierarchical; the name attached to memcached log statements +// will be "operator-sdk.controller_memcached" because SDKLog has name +// "operator-sdk". +var log = logf.Log.WithName("controller_memcached") + +func (r *ReconcileMemcached) Reconcile(request reconcile.Request) (reconcile.Result, error) { + // Create a logger for Reconcile() that includes "Request.Namespace" + // and "Request.Name" in each log record from this log statement. + reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) + reqLogger.Info("Reconciling Memcached.") + + memcached := &cachev1alpha1.Memcached{} + err := r.client.Get(context.TODO(), request.NamespacedName, memcached) + if err != nil { + if errors.IsNotFound(err) { + reqLogger.Info("Memcached resource not found. Ignoring since object must be deleted.") + return reconcile.Result{}, nil + } + return reconcile.Result{}, err + } + + found := &appsv1.Deployment{} + err = r.client.Get(context.TODO(), types.NamespacedName{Name: memcached.Name, Namespace: memcached.Namespace}, found) + if err != nil { + if errors.IsNotFound(err) { + dep := r.deploymentForMemcached(memcached) + // Include "Deployment.Namespace" and "Deployment.Name" in records + // produced by this particular log statement. "Request.Namespace" and + // "Request.Name" will also be included from reqLogger. + reqLogger.Info("Creating a new Deployment", "Deployment.Namespace", dep.Namespace, "Deployment.Name", dep.Name) + err = r.client.Create(context.TODO(), dep) + if err != nil { + // Include the error in records produced by this log statement. + reqLogger.Error(err, "failed to create new Deployment", "Deployment.Namespace", dep.Namespace, "Deployment.Name", dep.Name) + return reconcile.Result{}, err + } + } + return reconcile.Result{}, err + } + + ... +} +``` + +Log records will look like the following (from `reqLogger.Error()` above): + +``` +2018-11-08T00:00:25.700Z ERROR operator-sdk.controller_memcached pkg/controller/memcached/memcached_controller.go:118 failed to create new Deployment {"Request.Namespace", "memcached", "Request.Name", "memcached-operator", "Deployment.Namespace", "memcached", "Deployment.Name", "memcached-operator"} +``` + +## Non-default logging + +If you do not want to use `logr` as your logging tool, you can remove `logr`-specific statements without issue from your operator's code, including the `logr` [setup code][code_set_logger] in `cmd/manager/main.go`, and add your own. Note that removing `logr` setup code will prevent `controller-runtime` from logging. + + +[godoc_logr]:https://godoc.org/github.com/go-logr/logr +[repo_zapr]:https://godoc.org/github.com/go-logr/zapr +[godoc_logr_logger]:https://godoc.org/github.com/go-logr/logr#Logger +[site_struct_logging]:https://www.client9.com/structured-logging-in-golang/ +[code_memcached_controller]:../../example/memcached-operator/memcached_controller.go.tmpl +[code_set_logger]:https://github.com/operator-framework/operator-sdk/blob/948139171fff0e802c9e68f87cb95939941772ef/pkg/scaffold/cmd.go#L68-L72 diff --git a/example/memcached-operator/memcached_controller.go.tmpl b/example/memcached-operator/memcached_controller.go.tmpl index 0d8d8437090..4f83c41a59c 100644 --- a/example/memcached-operator/memcached_controller.go.tmpl +++ b/example/memcached-operator/memcached_controller.go.tmpl @@ -2,7 +2,6 @@ package memcached import ( "context" - "log" "reflect" cachev1alpha1 "github.com/example-inc/memcached-operator/pkg/apis/cache/v1alpha1" @@ -20,9 +19,12 @@ import ( "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" "sigs.k8s.io/controller-runtime/pkg/source" ) +var log = logf.Log.WithName("controller_memcached") + /** * USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller * business logic. Delete these comments after modifying this file.* @@ -85,7 +87,8 @@ type ReconcileMemcached struct { // The Controller will requeue the Request to be processed again if the returned error is non-nil or // Result.Requeue is true, otherwise upon completion it will remove the work from the queue. func (r *ReconcileMemcached) Reconcile(request reconcile.Request) (reconcile.Result, error) { - log.Printf("Reconciling Memcached %s/%s\n", request.Namespace, request.Name) + reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name) + reqLogger.Info("Reconciling Memcached") // Fetch the Memcached instance memcached := &cachev1alpha1.Memcached{} @@ -95,11 +98,11 @@ func (r *ReconcileMemcached) Reconcile(request reconcile.Request) (reconcile.Res // Request object not found, could have been deleted after reconcile request. // Owned objects are automatically garbage collected. For additional cleanup logic use finalizers. // Return and don't requeue - log.Printf("Memcached %s/%s not found. Ignoring since object must be deleted\n", request.Namespace, request.Name) + reqLogger.Info("Memcached resource not found. Ignoring since object must be deleted") return reconcile.Result{}, nil } // Error reading the object - requeue the request. - log.Printf("Failed to get Memcached: %v", err) + reqLogger.Error(err, "failed to get Memcached") return reconcile.Result{}, err } @@ -109,16 +112,16 @@ func (r *ReconcileMemcached) Reconcile(request reconcile.Request) (reconcile.Res if err != nil && errors.IsNotFound(err) { // Define a new deployment dep := r.deploymentForMemcached(memcached) - log.Printf("Creating a new Deployment %s/%s\n", dep.Namespace, dep.Name) + reqLogger.Info("Creating a new Deployment", "Deployment.Namespace", dep.Namespace, "Deployment.Name", dep.Name) err = r.client.Create(context.TODO(), dep) if err != nil { - log.Printf("Failed to create new Deployment: %v\n", err) + reqLogger.Error(err, "failed to create new Deployment", "Deployment.Namespace", dep.Namespace, "Deployment.Name", dep.Name) return reconcile.Result{}, err } // Deployment created successfully - return and requeue return reconcile.Result{Requeue: true}, nil } else if err != nil { - log.Printf("Failed to get Deployment: %v\n", err) + reqLogger.Error(err, "failed to get Deployment") return reconcile.Result{}, err } @@ -128,7 +131,7 @@ func (r *ReconcileMemcached) Reconcile(request reconcile.Request) (reconcile.Res found.Spec.Replicas = &size err = r.client.Update(context.TODO(), found) if err != nil { - log.Printf("Failed to update Deployment: %v\n", err) + reqLogger.Error(err, "failed to update Deployment", "Deployment.Namespace", found.Namespace, "Deployment.Name", found.Name) return reconcile.Result{}, err } // Spec updated - return and requeue @@ -142,7 +145,7 @@ func (r *ReconcileMemcached) Reconcile(request reconcile.Request) (reconcile.Res listOps := &client.ListOptions{Namespace: memcached.Namespace, LabelSelector: labelSelector} err = r.client.List(context.TODO(), listOps, podList) if err != nil { - log.Printf("Failed to list pods: %v", err) + reqLogger.Error(err, "failed to list pods", "Memcached.Namespace", memcached.Namespace, "Memcached.Name", memcached.Name) return reconcile.Result{}, err } podNames := getPodNames(podList.Items) @@ -152,7 +155,7 @@ func (r *ReconcileMemcached) Reconcile(request reconcile.Request) (reconcile.Res memcached.Status.Nodes = podNames err := r.client.Update(context.TODO(), memcached) if err != nil { - log.Printf("failed to update memcached status: %v", err) + reqLogger.Error(err, "failed to update Memcached status") return reconcile.Result{}, err } } diff --git a/hack/check_error_case.sh b/hack/check_error_case.sh index 6e6ecd05578..070da7bf31d 100755 --- a/hack/check_error_case.sh +++ b/hack/check_error_case.sh @@ -7,7 +7,7 @@ source "hack/lib/test_lib.sh" echo "Checking case of error messages..." allfiles=$(listFiles) -output=$(grep -Rn 'Fatalf("[[:upper:]]\|Errorf("[[:upper:]]\|errors.New("[[:upper:]]' $allfiles) +output=$(grep -ERn 'Fatal(f)?\("[[:upper:]]|Error(f)?\("[[:upper:]]|Error\((err|nil), "[[:upper:]]|errors.New\("[[:upper:]]' $allfiles) if [ -n "${output}" ]; then echo "Error messages in wrong case:" echo "${output}" diff --git a/internal/util/fileutil/file_util.go b/internal/util/fileutil/file_util.go index 995edc210f7..de2b36fb755 100644 --- a/internal/util/fileutil/file_util.go +++ b/internal/util/fileutil/file_util.go @@ -19,11 +19,11 @@ package fileutil import ( "fmt" "io" - "log" "os" "path/filepath" "sync" + log "github.com/sirupsen/logrus" "github.com/spf13/afero" ) diff --git a/internal/util/projutil/project_util.go b/internal/util/projutil/project_util.go index 377ddead6fc..68a5490ac33 100644 --- a/internal/util/projutil/project_util.go +++ b/internal/util/projutil/project_util.go @@ -15,11 +15,11 @@ package projutil import ( - "log" "os" "path/filepath" "strings" + log "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -50,7 +50,7 @@ func MustInProjectRoot() { // we are at the project root. _, err := os.Stat(buildDockerfile) if err != nil && os.IsNotExist(err) { - log.Fatalf("must run command in project root dir: %v", err) + log.Fatalf("must run command in project root dir: (%v)", err) } } diff --git a/pkg/ansible/controller/controller.go b/pkg/ansible/controller/controller.go index 262cb41380e..12c98d4ea16 100644 --- a/pkg/ansible/controller/controller.go +++ b/pkg/ansible/controller/controller.go @@ -16,23 +16,25 @@ package controller import ( "fmt" - "log" + "os" "strings" "time" "github.com/operator-framework/operator-sdk/pkg/ansible/events" "github.com/operator-framework/operator-sdk/pkg/ansible/runner" - "github.com/sirupsen/logrus" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "sigs.k8s.io/controller-runtime/pkg/controller" crthandler "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/manager" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" "sigs.k8s.io/controller-runtime/pkg/source" ) +var log = logf.Log.WithName("ansible-controller") + // Options - options for your controller type Options struct { EventHandlers []events.EventHandler @@ -44,7 +46,7 @@ type Options struct { // Add - Creates a new ansible operator controller and adds it to the manager func Add(mgr manager.Manager, options Options) { - logrus.Infof("Watching %s/%v, %s", options.GVK.Group, options.GVK.Version, options.GVK.Kind) + log.Info("Watching resource", "Options.Group", options.GVK.Group, "Options.Version", options.GVK.Version, "Options.Kind", options.GVK.Kind) if options.EventHandlers == nil { options.EventHandlers = []events.EventHandler{} } @@ -70,11 +72,13 @@ func Add(mgr manager.Manager, options Options) { Reconciler: aor, }) if err != nil { - log.Fatal(err) + log.Error(err, "") + os.Exit(1) } u := &unstructured.Unstructured{} u.SetGroupVersionKind(options.GVK) if err := c.Watch(&source.Kind{Type: u}, &crthandler.EnqueueRequestForObject{}); err != nil { - log.Fatal(err) + log.Error(err, "") + os.Exit(1) } } diff --git a/pkg/ansible/controller/reconcile.go b/pkg/ansible/controller/reconcile.go index f10d684fc9c..431b80f7a3f 100644 --- a/pkg/ansible/controller/reconcile.go +++ b/pkg/ansible/controller/reconcile.go @@ -30,7 +30,6 @@ import ( "github.com/operator-framework/operator-sdk/pkg/ansible/runner" "github.com/operator-framework/operator-sdk/pkg/ansible/runner/eventapi" - "github.com/sirupsen/logrus" "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -38,6 +37,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" ) const ( @@ -69,12 +69,11 @@ func (r *AnsibleOperatorReconciler) Reconcile(request reconcile.Request) (reconc } ident := strconv.Itoa(rand.Int()) - logger := logrus.WithFields(logrus.Fields{ - "component": "reconciler", - "job": ident, - "name": u.GetName(), - "namespace": u.GetNamespace(), - }) + logger := logf.Log.WithName("reconciler").WithValues( + "job", ident, + "name", u.GetName(), + "namespace", u.GetNamespace(), + ) reconcileResult := reconcile.Result{RequeueAfter: r.ReconcilePeriod} if ds, ok := u.GetAnnotations()[ReconcilePeriodAnnotation]; ok { @@ -90,7 +89,7 @@ func (r *AnsibleOperatorReconciler) Reconcile(request reconcile.Request) (reconc pendingFinalizers := u.GetFinalizers() // If the resource is being deleted we don't want to add the finalizer again if finalizerExists && !deleted && !contains(pendingFinalizers, finalizer) { - logger.Debugf("Adding finalizer %s to resource", finalizer) + logger.V(1).Info("Adding finalizer to resource", "Finalizer", finalizer) finalizers := append(pendingFinalizers, finalizer) u.SetFinalizers(finalizers) err := r.Client.Update(context.TODO(), u) @@ -106,7 +105,7 @@ func (r *AnsibleOperatorReconciler) Reconcile(request reconcile.Request) (reconc spec := u.Object["spec"] _, ok := spec.(map[string]interface{}) if !ok { - logger.Debugf("spec was not found") + logger.V(1).Info("spec was not found") u.Object["spec"] = map[string]interface{}{} err = r.Client.Update(context.TODO(), u) if err != nil { @@ -180,15 +179,14 @@ func (r *AnsibleOperatorReconciler) Reconcile(request reconcile.Request) (reconc } } if statusEvent.Event == "" { - msg := "did not receive playbook_on_stats event" - logger.Error(msg) + eventErr := errors.New("did not receive playbook_on_stats event") stdout, err := result.Stdout() if err != nil { - logger.Infof("failed to get ansible-runner stdout: %s\n", err.Error()) - } else { - logger.Error(stdout) + logger.Error(err, "failed to get ansible-runner stdout") + return reconcileResult, err } - return reconcileResult, errors.New(msg) + logger.Error(eventErr, stdout) + return reconcileResult, eventErr } // We only want to update the CustomResource once, so we'll track changes and do it at the end diff --git a/pkg/ansible/controller/status/types.go b/pkg/ansible/controller/status/types.go index 8da061710c3..396ac608bd2 100644 --- a/pkg/ansible/controller/status/types.go +++ b/pkg/ansible/controller/status/types.go @@ -18,11 +18,14 @@ import ( "time" "github.com/operator-framework/operator-sdk/pkg/ansible/runner/eventapi" - "github.com/sirupsen/logrus" + "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" ) +var log = logf.Log.WithName("controller.status") + const ( host = "localhost" ) @@ -128,7 +131,7 @@ func createConditionFromMap(cm map[string]interface{}) Condition { if ok { t, err := time.Parse("2006-01-02T15:04:05Z", ltts) if err != nil { - logrus.Warningf("unable to parse time for status condition: %v", ltts) + log.Info("unable to parse time for status condition", "Time", ltts) } else { ltt = metav1.NewTime(t) } @@ -158,7 +161,7 @@ func CreateFromMap(statusMap map[string]interface{}) Status { for _, ci := range conditionsInterface { cm, ok := ci.(map[string]interface{}) if !ok { - logrus.Warningf("unknown condition, removing condition: %v", ci) + log.Info("unknown condition, removing condition", "ConditionInterface", ci) continue } conditions = append(conditions, createConditionFromMap(cm)) diff --git a/pkg/ansible/events/log_events.go b/pkg/ansible/events/log_events.go index b7cce7066e8..271be8e0d8a 100644 --- a/pkg/ansible/events/log_events.go +++ b/pkg/ansible/events/log_events.go @@ -15,9 +15,12 @@ package events import ( + "errors" + "github.com/operator-framework/operator-sdk/pkg/ansible/runner/eventapi" - "github.com/sirupsen/logrus" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" ) // LogLevel - Levelt for the logging to take place. @@ -44,44 +47,48 @@ type loggingEventHandler struct { } func (l loggingEventHandler) Handle(ident string, u *unstructured.Unstructured, e eventapi.JobEvent) { - log := logrus.WithFields(logrus.Fields{ - "component": "logging_event_handler", - "name": u.GetName(), - "namespace": u.GetNamespace(), - "gvk": u.GroupVersionKind().String(), - "event_type": e.Event, - "job": ident, - }) if l.LogLevel == Nothing { return } - // log only the following for the 'Tasks' LogLevel + + logger := logf.Log.WithName("logging_event_handler").WithValues( + "name", u.GetName(), + "namespace", u.GetNamespace(), + "gvk", u.GroupVersionKind().String(), + "event_type", e.Event, + "job", ident, + ) + + // logger only the following for the 'Tasks' LogLevel t, ok := e.EventData["task"] if ok { setFactAction := e.EventData["task_action"] == eventapi.TaskActionSetFact debugAction := e.EventData["task_action"] == eventapi.TaskActionDebug if e.Event == eventapi.EventPlaybookOnTaskStart && !setFactAction && !debugAction { - log.Infof("[playbook task]: %s", e.EventData["name"]) + logger.Info("[playbook task]", "EventData.Name", e.EventData["name"]) return } if e.Event == eventapi.EventRunnerOnOk && debugAction { - log.Infof("[playbook debug]: %v", e.EventData["task_args"]) + logger.V(1).Info("[playbook debug]", "EventData.TaskArgs", e.EventData["task_args"]) return } if e.Event == eventapi.EventRunnerOnFailed { - log.Errorf("[failed]: [playbook task] '%s' failed with task_args - %v", - t, e.EventData["task_args"]) - taskPath, ok := e.EventData["task_path"] - if ok { - log.Errorf("failed task: %s\n", taskPath) + errKVs := []interface{}{ + "EventData.Task", t, + "EventData.TaskArgs", e.EventData["task_args"], + } + if taskPath, ok := e.EventData["task_path"]; ok { + errKVs = append(errKVs, "EventData.FailedTaskPath", taskPath) } + logger.Error(errors.New("[playbook task failed]"), "", errKVs...) return } } + // log everything else for the 'Everything' LogLevel if l.LogLevel == Everything { - log.Infof("event: %#v", e.EventData) + logger.Info("", "EventData", e.EventData) } } diff --git a/pkg/ansible/operator/operator.go b/pkg/ansible/operator/operator.go index 394bacaf0a1..f828fac382d 100644 --- a/pkg/ansible/operator/operator.go +++ b/pkg/ansible/operator/operator.go @@ -20,10 +20,10 @@ import ( "github.com/operator-framework/operator-sdk/pkg/ansible/controller" "github.com/operator-framework/operator-sdk/pkg/ansible/runner" + "sigs.k8s.io/controller-runtime/pkg/manager" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" "sigs.k8s.io/controller-runtime/pkg/runtime/signals" - - "github.com/sirupsen/logrus" ) // Run - A blocking function which starts a controller-runtime manager @@ -32,7 +32,7 @@ import ( func Run(done chan error, mgr manager.Manager, watchesPath string, reconcilePeriod time.Duration) { watches, err := runner.NewFromWatches(watchesPath) if err != nil { - logrus.Error("Failed to get watches") + logf.Log.WithName("manager").Error(err, "failed to get watches") done <- err return } diff --git a/pkg/ansible/proxy/kubectl.go b/pkg/ansible/proxy/kubectl.go index 3c24243b7e6..bfe3db4ebd4 100644 --- a/pkg/ansible/proxy/kubectl.go +++ b/pkg/ansible/proxy/kubectl.go @@ -22,7 +22,6 @@ package proxy import ( "fmt" - "log" "net" "net/http" "net/url" @@ -36,8 +35,11 @@ import ( k8sproxy "k8s.io/apimachinery/pkg/util/proxy" "k8s.io/client-go/rest" "k8s.io/client-go/transport" + logf "sigs.k8s.io/controller-runtime/pkg/runtime/log" ) +var log = logf.Log.WithName("proxy") + const ( // DefaultHostAcceptRE is the default value for which hosts to accept. DefaultHostAcceptRE = "^localhost$,^127\\.0\\.0\\.1$,^\\[::1\\]$" @@ -91,7 +93,8 @@ func MakeRegexpArray(str string) ([]*regexp.Regexp, error) { func MakeRegexpArrayOrDie(str string) []*regexp.Regexp { result, err := MakeRegexpArray(str) if err != nil { - log.Fatalf("error compiling re: %v", err) + log.Error(err, "error compiling re") + os.Exit(1) } return result } @@ -99,7 +102,7 @@ func MakeRegexpArrayOrDie(str string) []*regexp.Regexp { func matchesRegexp(str string, regexps []*regexp.Regexp) bool { for _, re := range regexps { if re.MatchString(str) { - log.Printf("%v matched %s", str, re) + log.Info("matched found", "MatchString", str, "Regexp", re) return true } } @@ -139,11 +142,11 @@ func extractHost(header string) (host string) { func (f *FilterServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) { host := extractHost(req.Host) if f.accept(req.Method, req.URL.Path, host) { - log.Printf("Filter accepting %v %v %v", req.Method, req.URL.Path, host) + log.Info("Filter acception", "Request.Method", req.Method, "Request.URL", req.URL.Path, "Host", host) f.delegate.ServeHTTP(rw, req) return } - log.Printf("Filter rejecting %v %v %v", req.Method, req.URL.Path, host) + log.Info("Filter rejection", "Request.Method", req.Method, "Request.URL", req.URL.Path, "Host", host) rw.WriteHeader(http.StatusForbidden) rw.Write([]byte("