Skip to content

Commit 2df7ff8

Browse files
cli: remove global logger; inject logger via dependency injection
Resolves #585 Remove the package-level `Logger` variable from `cli/cmd` and replace all usages with contextual child loggers injected through `Opts` structs and service constructors. - cli/cmd/root.go: remove `var Logger *log.ZapLogger` and its init assignment - cli/cmd/capture/capture.go: add `logger` field to `Opts` struct, init in NewCommand() - cli/cmd/capture/create.go: replace `retinacmd.Logger` with `opts.logger` - cli/cmd/capture/delete.go: replace `retinacmd.Logger` with `opts.logger` - cli/cmd/capture/download.go: add `logger` to `DownloadService`, replace usages Signed-off-by: mail2sudheerobbu-oss <mail2sudheerobbu@gmail.com>
1 parent 73a8094 commit 2df7ff8

6 files changed

Lines changed: 59 additions & 56 deletions

File tree

cli/cmd/capture/capture.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package capture
66
import (
77
"time"
88

9+
"github.com/microsoft/retina/pkg/log"
910
"github.com/spf13/cobra"
1011
"k8s.io/cli-runtime/pkg/genericclioptions"
1112
"k8s.io/client-go/kubernetes"
@@ -39,6 +40,7 @@ type Opts struct {
3940
s3Region string
4041
s3SecretAccessKey string
4142
tcpdumpFilter string
43+
logger *log.ZapLogger
4244
}
4345

4446
var opts = Opts{

cli/cmd/capture/create.go

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"k8s.io/kubectl/pkg/util/i18n"
2424
"k8s.io/kubectl/pkg/util/templates"
2525

26-
retinacmd "github.com/microsoft/retina/cli/cmd"
2726
retinav1alpha1 "github.com/microsoft/retina/crd/api/v1alpha1"
2827
"github.com/microsoft/retina/internal/buildinfo"
2928
pkgcapture "github.com/microsoft/retina/pkg/capture"
@@ -109,47 +108,47 @@ func create(kubeClient kubernetes.Interface) error {
109108

110109
jobsCreated, err := createJobs(ctx, kubeClient, capture)
111110
if err != nil {
112-
retinacmd.Logger.Error("Failed to create job", zap.Error(err))
111+
opts.logger.Error("Failed to create job", zap.Error(err))
113112
return err
114113
}
115114
if opts.nowait {
116-
retinacmd.Logger.Info("Please manually delete all capture jobs")
115+
opts.logger.Info("Please manually delete all capture jobs")
117116
if capture.Spec.OutputConfiguration.BlobUpload != nil {
118-
retinacmd.Logger.Info("Please manually delete capture secret", zap.String("namespace", *opts.Namespace), zap.String("secret name", *capture.Spec.OutputConfiguration.BlobUpload))
117+
opts.logger.Info("Please manually delete capture secret", zap.String("namespace", *opts.Namespace), zap.String("secret name", *capture.Spec.OutputConfiguration.BlobUpload))
119118
}
120119
if capture.Spec.OutputConfiguration.S3Upload != nil && capture.Spec.OutputConfiguration.S3Upload.SecretName != "" {
121-
retinacmd.Logger.Info("Please manually delete capture secret", zap.String("namespace", *opts.Namespace), zap.String("secret name", capture.Spec.OutputConfiguration.S3Upload.SecretName))
120+
opts.logger.Info("Please manually delete capture secret", zap.String("namespace", *opts.Namespace), zap.String("secret name", capture.Spec.OutputConfiguration.S3Upload.SecretName))
122121
}
123122
printCaptureResult(jobsCreated)
124123
return nil
125124
}
126125

127126
// Wait until all jobs finish then delete the jobs before the timeout, otherwise print jobs created to
128127
// let the customer recycle them.
129-
retinacmd.Logger.Info("Waiting for capture jobs to finish")
128+
opts.logger.Info("Waiting for capture jobs to finish")
130129

131130
allJobsCompleted := waitUntilJobsComplete(ctx, kubeClient, jobsCreated)
132131

133132
// Delete all jobs created only if they all completed, otherwise keep the jobs for debugging.
134133
if allJobsCompleted {
135-
retinacmd.Logger.Info("Deleting jobs as all jobs are completed")
134+
opts.logger.Info("Deleting jobs as all jobs are completed")
136135
jobsFailedToDelete := deleteJobs(ctx, kubeClient, jobsCreated)
137136
if len(jobsFailedToDelete) != 0 {
138-
retinacmd.Logger.Info("Please manually delete capture jobs failed to delete", zap.String("namespace", *opts.Namespace), zap.String("job list", strings.Join(jobsFailedToDelete, ",")))
137+
opts.logger.Info("Please manually delete capture jobs failed to delete", zap.String("namespace", *opts.Namespace), zap.String("job list", strings.Join(jobsFailedToDelete, ",")))
139138
}
140139

141140
if capture.Spec.OutputConfiguration.BlobUpload != nil {
142141
err = deleteSecret(ctx, kubeClient, capture.Spec.OutputConfiguration.BlobUpload)
143142
if err != nil {
144-
retinacmd.Logger.Error("Failed to delete capture secret, please manually delete it",
143+
opts.logger.Error("Failed to delete capture secret, please manually delete it",
145144
zap.String("namespace", *opts.Namespace), zap.String("secret name", *capture.Spec.OutputConfiguration.BlobUpload), zap.Error(err))
146145
}
147146
}
148147

149148
if capture.Spec.OutputConfiguration.S3Upload != nil && capture.Spec.OutputConfiguration.S3Upload.SecretName != "" {
150149
err = deleteSecret(ctx, kubeClient, &capture.Spec.OutputConfiguration.S3Upload.SecretName)
151150
if err != nil {
152-
retinacmd.Logger.Error("Failed to delete capture secret, please manually delete it",
151+
opts.logger.Error("Failed to delete capture secret, please manually delete it",
153152
zap.String("namespace", *opts.Namespace),
154153
zap.String("secret name", capture.Spec.OutputConfiguration.S3Upload.SecretName),
155154
zap.Error(err),
@@ -158,13 +157,13 @@ func create(kubeClient kubernetes.Interface) error {
158157
}
159158

160159
if len(jobsFailedToDelete) == 0 && err == nil {
161-
retinacmd.Logger.Info("Done for deleting jobs")
160+
opts.logger.Info("Done for deleting jobs")
162161
}
163162
return nil
164163
}
165164

166-
retinacmd.Logger.Info("Not all job are completed in the given time")
167-
retinacmd.Logger.Info("Please manually delete the Capture")
165+
opts.logger.Info("Not all job are completed in the given time")
166+
opts.logger.Info("Please manually delete the Capture")
168167

169168
return getCaptureAndPrintCaptureResult(ctx, kubeClient, capture.Name, *opts.Namespace)
170169
}
@@ -299,17 +298,17 @@ func createCaptureF(ctx context.Context, kubeClient kubernetes.Interface) (*reti
299298
},
300299
}
301300

302-
retinacmd.Logger.Info(fmt.Sprintf("Capture timestamp: %s", timestamp))
301+
opts.logger.Info(fmt.Sprintf("Capture timestamp: %s", timestamp))
303302

304303
if opts.duration != 0 {
305-
retinacmd.Logger.Info(fmt.Sprintf("The capture duration is set to %s", opts.duration))
304+
opts.logger.Info(fmt.Sprintf("The capture duration is set to %s", opts.duration))
306305
capture.Spec.CaptureConfiguration.CaptureOption.Duration = &metav1.Duration{Duration: opts.duration}
307306
}
308307

309308
if opts.namespaceSelectors != "" || opts.podSelectors != "" || opts.podNames != "" {
310309
// if node selector is using the default value (aka hasn't been set by user), set it to nil to prevent clash with namespace and pod selector
311310
if opts.nodeSelectors == DefaultNodeSelectors {
312-
retinacmd.Logger.Info("Overriding default node selectors value and setting it to nil. Using namespace, pod selectors, or pod names. " +
311+
opts.logger.Info("Overriding default node selectors value and setting it to nil. Using namespace, pod selectors, or pod names. " +
313312
"To use node selector, please remove namespace and pod selectors.")
314313
opts.nodeSelectors = ""
315314
}
@@ -365,17 +364,17 @@ func createCaptureF(ctx context.Context, kubeClient kubernetes.Interface) (*reti
365364
for i := range podNameSlice {
366365
podNameSlice[i] = strings.TrimSpace(podNameSlice[i])
367366
}
368-
retinacmd.Logger.Info(fmt.Sprintf("Capturing on specific pods: %v", podNameSlice))
367+
opts.logger.Info(fmt.Sprintf("Capturing on specific pods: %v", podNameSlice))
369368
capture.Spec.CaptureConfiguration.CaptureTarget.PodNames = podNameSlice
370369
}
371370

372371
if opts.maxSize != 0 {
373-
retinacmd.Logger.Info(fmt.Sprintf("The capture file max size is set to %dMB", opts.maxSize))
372+
opts.logger.Info(fmt.Sprintf("The capture file max size is set to %dMB", opts.maxSize))
374373
capture.Spec.CaptureConfiguration.CaptureOption.MaxCaptureSize = &opts.maxSize
375374
}
376375

377376
if opts.packetSize != 0 {
378-
retinacmd.Logger.Info(fmt.Sprintf("The capture packet size is set to %d bytes", opts.packetSize))
377+
opts.logger.Info(fmt.Sprintf("The capture packet size is set to %d bytes", opts.packetSize))
379378
capture.Spec.CaptureConfiguration.CaptureOption.PacketSize = &opts.packetSize
380379
}
381380

@@ -384,7 +383,7 @@ func createCaptureF(ctx context.Context, kubeClient kubernetes.Interface) (*reti
384383
for i := range interfaceSlice {
385384
interfaceSlice[i] = strings.TrimSpace(interfaceSlice[i])
386385
}
387-
retinacmd.Logger.Info(fmt.Sprintf("Capturing on specific interfaces: %v", interfaceSlice))
386+
opts.logger.Info(fmt.Sprintf("Capturing on specific interfaces: %v", interfaceSlice))
388387
capture.Spec.CaptureConfiguration.CaptureOption.Interfaces = interfaceSlice
389388
}
390389

@@ -446,7 +445,7 @@ func getCLICaptureConfig() config.CaptureConfig {
446445
}
447446

448447
func createJobs(ctx context.Context, kubeClient kubernetes.Interface, capture *retinav1alpha1.Capture) ([]batchv1.Job, error) {
449-
translator := pkgcapture.NewCaptureToPodTranslator(kubeClient, retinacmd.Logger, getCLICaptureConfig())
448+
translator := pkgcapture.NewCaptureToPodTranslator(kubeClient, opts.logger, getCLICaptureConfig())
450449
jobs, err := translator.TranslateCaptureToJobs(ctx, capture)
451450
if err != nil {
452451
return nil, err
@@ -459,7 +458,7 @@ func createJobs(ctx context.Context, kubeClient kubernetes.Interface, capture *r
459458
return nil, err
460459
}
461460
jobsCreated = append(jobsCreated, *jobCreated)
462-
retinacmd.Logger.Info("Packet capture job is created", zap.String("namespace", *opts.Namespace), zap.String("capture job", jobCreated.Name))
461+
opts.logger.Info("Packet capture job is created", zap.String("namespace", *opts.Namespace), zap.String("capture job", jobCreated.Name))
463462
}
464463
return jobsCreated, nil
465464
}
@@ -478,7 +477,7 @@ func waitUntilJobsComplete(ctx context.Context, kubeClient kubernetes.Interface,
478477
if period < opts.duration/10 {
479478
period = opts.duration / 10
480479
}
481-
retinacmd.Logger.Info(fmt.Sprintf("Waiting timeout is set to %s", deadline))
480+
opts.logger.Info(fmt.Sprintf("Waiting timeout is set to %s", deadline))
482481

483482
ctx, cancel := context.WithTimeout(ctx, deadline)
484483
defer cancel()
@@ -490,7 +489,7 @@ func waitUntilJobsComplete(ctx context.Context, kubeClient kubernetes.Interface,
490489
for _, job := range jobs {
491490
jobRet, err := kubeClient.BatchV1().Jobs(job.Namespace).Get(ctx, job.Name, metav1.GetOptions{})
492491
if err != nil {
493-
retinacmd.Logger.Error("Failed to get job", zap.String("namespace", job.Namespace), zap.String("job name", job.Name), zap.Error(err))
492+
opts.logger.Error("Failed to get job", zap.String("namespace", job.Namespace), zap.String("job name", job.Name), zap.Error(err))
494493
jobsIncompleted = append(jobsIncompleted, job.Name)
495494
continue
496495
}
@@ -502,7 +501,7 @@ func waitUntilJobsComplete(ctx context.Context, kubeClient kubernetes.Interface,
502501
}
503502

504503
if len(jobsIncompleted) != 0 {
505-
retinacmd.Logger.Info("Not all jobs are completed",
504+
opts.logger.Info("Not all jobs are completed",
506505
zap.String("namespace", *opts.Namespace),
507506
zap.String("Completed jobs", strings.Join(jobsCompleted, ",")),
508507
zap.String("Uncompleted packet capture jobs", strings.Join(jobsIncompleted, ",")),
@@ -528,7 +527,7 @@ func deleteJobs(ctx context.Context, kubeClient kubernetes.Interface, jobs []bat
528527
})
529528
if err != nil {
530529
jobsFailedtoDelete = append(jobsFailedtoDelete, job.Name)
531-
retinacmd.Logger.Error("Failed to delete job", zap.String("namespace", job.Namespace), zap.String("job name", job.Name), zap.Error(err))
530+
opts.logger.Error("Failed to delete job", zap.String("namespace", job.Namespace), zap.String("job name", job.Name), zap.Error(err))
532531
}
533532
}
534533
return jobsFailedtoDelete

cli/cmd/capture/delete.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"os/signal"
1010
"syscall"
1111

12-
retinacmd "github.com/microsoft/retina/cli/cmd"
1312
captureConstants "github.com/microsoft/retina/pkg/capture/constants"
1413
"github.com/microsoft/retina/pkg/label"
1514
"github.com/pkg/errors"
@@ -70,7 +69,7 @@ func NewDeleteSubCommand(kubeClient kubernetes.Interface) *cobra.Command {
7069
if err := kubeClient.BatchV1().Jobs(jobList.Items[idx].Namespace).Delete(ctx, jobList.Items[idx].Name, metav1.DeleteOptions{
7170
PropagationPolicy: &deletePropagationBackground,
7271
}); err != nil {
73-
retinacmd.Logger.Info("Failed to delete job", zap.String("job name", jobList.Items[idx].Name), zap.Error(err))
72+
opts.logger.Info("Failed to delete job", zap.String("job name", jobList.Items[idx].Name), zap.Error(err))
7473
}
7574
}
7675

@@ -82,7 +81,7 @@ func NewDeleteSubCommand(kubeClient kubernetes.Interface) *cobra.Command {
8281
break
8382
}
8483
}
85-
retinacmd.Logger.Info(fmt.Sprintf("Retina Capture %q delete", *opts.Name))
84+
opts.logger.Info(fmt.Sprintf("Retina Capture %q delete", *opts.Name))
8685

8786
return nil
8887
},

cli/cmd/capture/download.go

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ import (
2020
"time"
2121

2222
"github.com/Azure/azure-sdk-for-go/storage"
23-
retinacmd "github.com/microsoft/retina/cli/cmd"
2423
captureConstants "github.com/microsoft/retina/pkg/capture/constants"
2524
captureFile "github.com/microsoft/retina/pkg/capture/file"
2625
captureUtils "github.com/microsoft/retina/pkg/capture/utils"
2726
captureLabels "github.com/microsoft/retina/pkg/label"
27+
"github.com/microsoft/retina/pkg/log"
2828
"github.com/spf13/cobra"
2929
"github.com/spf13/viper"
3030
"go.uber.org/zap"
@@ -104,6 +104,7 @@ type DownloadService struct {
104104
kubeClient kubernetes.Interface
105105
config *rest.Config
106106
namespace string
107+
logger *log.ZapLogger
107108
}
108109

109110
// Key represents a unique capture identifier
@@ -115,14 +116,15 @@ type Key struct {
115116
// NewDownloadService creates a new download service with shared dependencies
116117
func NewDownloadService(kubeClient kubernetes.Interface, config *rest.Config, namespace string) *DownloadService {
117118
return &DownloadService{
119+
logger: log.Logger().Named("retina-capture-download"),
118120
kubeClient: kubeClient,
119121
config: config,
120122
namespace: namespace,
121123
}
122124
}
123125

124-
func getDownloadCmd(node *corev1.Node, hostPath, fileName string) (*DownloadCmd, error) {
125-
nodeOS, err := getNodeOS(node)
126+
func (ds *DownloadService) getDownloadCmd(node *corev1.Node, hostPath, fileName string) (*DownloadCmd, error) {
127+
nodeOS, err := ds.getNodeOS(node)
126128
if err != nil {
127129
return nil, err
128130
}
@@ -136,7 +138,7 @@ func getDownloadCmd(node *corev1.Node, hostPath, fileName string) (*DownloadCmd,
136138
srcFilePath := "C:\\host" + strings.ReplaceAll(hostPath, "/", "\\") + "\\" + fileName + ".tar.gz"
137139
mountPath := "C:\\host" + strings.ReplaceAll(hostPath, "/", "\\")
138140
return &DownloadCmd{
139-
ContainerImage: getWindowsContainerImage(node),
141+
ContainerImage: ds.getWindowsContainerImage(node),
140142
SrcFilePath: srcFilePath,
141143
MountPath: mountPath,
142144
KeepAliveCommand: []string{"cmd", "/c", "echo Download pod ready & ping -n 3601 127.0.0.1 > nul"},
@@ -159,24 +161,24 @@ func getDownloadCmd(node *corev1.Node, hostPath, fileName string) (*DownloadCmd,
159161
}
160162
}
161163

162-
func getNodeOS(node *corev1.Node) (NodeOS, error) {
164+
func (ds *DownloadService) getNodeOS(node *corev1.Node) (NodeOS, error) {
163165
nodeOS := strings.ToLower(node.Status.NodeInfo.OperatingSystem)
164166

165167
if strings.Contains(nodeOS, "windows") {
166-
retinacmd.Logger.Info("Detected node OS: Windows", zap.String("node", node.Name), zap.String("os", node.Status.NodeInfo.OperatingSystem))
168+
ds.logger.Info("Detected node OS: Windows", zap.String("node", node.Name), zap.String("os", node.Status.NodeInfo.OperatingSystem))
167169
return Windows, nil
168170
}
169171

170172
if strings.Contains(nodeOS, "linux") {
171-
retinacmd.Logger.Info("Detected node OS: Linux", zap.String("node", node.Name), zap.String("os", node.Status.NodeInfo.OperatingSystem))
173+
ds.logger.Info("Detected node OS: Linux", zap.String("node", node.Name), zap.String("os", node.Status.NodeInfo.OperatingSystem))
172174
return Linux, nil
173175
}
174176

175177
return nil, fmt.Errorf("unsupported operating system: %s: %w", node.Status.NodeInfo.OperatingSystem, ErrUnsupportedNodeOS)
176178
}
177179

178180
// Detects the Windows LTSC version and returns the appropriate nanoserver image
179-
func getWindowsContainerImage(node *corev1.Node) string {
181+
func (ds *DownloadService) getWindowsContainerImage(node *corev1.Node) string {
180182
osImage := strings.ToLower(node.Status.NodeInfo.OSImage)
181183

182184
var suffix string
@@ -188,14 +190,14 @@ func getWindowsContainerImage(node *corev1.Node) string {
188190
case strings.Contains(osImage, "2016"):
189191
suffix = "ltsc2016"
190192
default:
191-
retinacmd.Logger.Warn("Could not determine Windows LTSC version, defaulting to ltsc2022",
193+
ds.logger.Warn("Could not determine Windows LTSC version, defaulting to ltsc2022",
192194
zap.String("node", node.Name),
193195
zap.String("osImage", osImage))
194196
suffix = "ltsc2022"
195197
}
196198

197199
containerImage := "mcr.microsoft.com/windows/nanoserver:" + suffix
198-
retinacmd.Logger.Info("Selected Windows container image", zap.String("image", containerImage))
200+
ds.logger.Info("Selected Windows container image", zap.String("image", containerImage))
199201

200202
return containerImage
201203
}
@@ -290,7 +292,7 @@ func (ds *DownloadService) DownloadFileContent(ctx context.Context, nodeName, ho
290292
return nil, errors.Join(ErrGetNodeInfo, err)
291293
}
292294

293-
downloadCmd, err := getDownloadCmd(node, hostPath, fileName)
295+
downloadCmd, err := ds.getDownloadCmd(node, hostPath, fileName)
294296
if err != nil {
295297
return nil, err
296298
}
@@ -305,7 +307,7 @@ func (ds *DownloadService) DownloadFileContent(ctx context.Context, nodeName, ho
305307
defer func() {
306308
cleanupErr := ds.kubeClient.CoreV1().Pods(ds.namespace).Delete(ctx, downloadPod.Name, metav1.DeleteOptions{})
307309
if cleanupErr != nil {
308-
retinacmd.Logger.Warn("Failed to clean up debug pod", zap.String("name", downloadPod.Name), zap.Error(cleanupErr))
310+
ds.logger.Warn("Failed to clean up debug pod", zap.String("name", downloadPod.Name), zap.Error(cleanupErr))
309311
}
310312
}()
311313

@@ -481,15 +483,16 @@ func (ds *DownloadService) createDownloadExec(ctx context.Context, pod *corev1.P
481483
}
482484

483485
func downloadFromBlob() error {
486+
l := log.Logger().Named("retina-capture-download")
484487
u, err := url.Parse(blobURL)
485488
if err != nil {
486-
retinacmd.Logger.Error("err: ", zap.Error(err))
489+
l.Error("err: ", zap.Error(err))
487490
return fmt.Errorf("failed to parse SAS URL %s: %w", blobURL, err)
488491
}
489492

490493
b, err := storage.NewAccountSASClientFromEndpointToken(u.String(), u.Query().Encode())
491494
if err != nil {
492-
retinacmd.Logger.Error("err: ", zap.Error(err))
495+
l.Error("err: ", zap.Error(err))
493496
return fmt.Errorf("failed to create storage account client: %w", err)
494497
}
495498

@@ -501,12 +504,12 @@ func downloadFromBlob() error {
501504
params := storage.ListBlobsParameters{Prefix: *opts.Name}
502505
blobList, err := blobService.GetContainerReference(containerName).ListBlobs(params)
503506
if err != nil {
504-
retinacmd.Logger.Error("err: ", zap.Error(err))
507+
l.Error("err: ", zap.Error(err))
505508
return fmt.Errorf("failed to list blobstore: %w", err)
506509
}
507510

508511
if len(blobList.Blobs) == 0 {
509-
retinacmd.Logger.Error("err: ", zap.Error(err))
512+
l.Error("err: ", zap.Error(err))
510513
return fmt.Errorf("%w: %s", ErrNoBlobsFound, *opts.Name)
511514
}
512515

@@ -520,21 +523,21 @@ func downloadFromBlob() error {
520523
blobRef := blobService.GetContainerReference(containerName).GetBlobReference(blob.Name)
521524
readCloser, err := blobRef.Get(&storage.GetBlobOptions{})
522525
if err != nil {
523-
retinacmd.Logger.Error("err: ", zap.Error(err))
526+
l.Error("err: ", zap.Error(err))
524527
return fmt.Errorf("failed to read from blobstore: %w", err)
525528
}
526529

527530
blobData, err := io.ReadAll(readCloser)
528531
readCloser.Close()
529532
if err != nil {
530-
retinacmd.Logger.Error("err: ", zap.Error(err))
533+
l.Error("err: ", zap.Error(err))
531534
return fmt.Errorf("failed to obtain blob from blobstore: %w", err)
532535
}
533536

534537
outputFile := filepath.Join(outputPath, blob.Name)
535538
err = os.WriteFile(outputFile, blobData, 0o600)
536539
if err != nil {
537-
retinacmd.Logger.Error("err: ", zap.Error(err))
540+
l.Error("err: ", zap.Error(err))
538541
return fmt.Errorf("failed to write file: %w", err)
539542
}
540543

0 commit comments

Comments
 (0)