Skip to content

Commit af08133

Browse files
committed
feat: add verbose logging option to controller-gen
1 parent 1ad88b0 commit af08133

File tree

4 files changed

+98
-1
lines changed

4 files changed

+98
-1
lines changed

pkg/crd/gen.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,30 +134,58 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
134134
GenerateEmbeddedObjectMeta: g.GenerateEmbeddedObjectMeta != nil && *g.GenerateEmbeddedObjectMeta,
135135
}
136136

137+
if ctx.Logger != nil {
138+
ctx.Logger.Debug("starting CRD generation", "ignoreUnexported", parser.IgnoreUnexportedFields, "allowDangerous", parser.AllowDangerousTypes)
139+
}
140+
137141
AddKnownTypes(parser)
138142
for _, root := range ctx.Roots {
139143
parser.NeedPackage(root)
144+
if ctx.Logger != nil {
145+
ctx.Logger.Debug("processing package", "package", root.PkgPath)
146+
}
140147
}
141148

142149
metav1Pkg := FindMetav1(ctx.Roots)
143150
if metav1Pkg == nil {
144151
// no objects in the roots, since nothing imported metav1
152+
if ctx.Logger != nil {
153+
ctx.Logger.Debug("no metav1 package found in roots, no CRDs to generate")
154+
}
145155
return nil
146156
}
147157

158+
if ctx.Logger != nil {
159+
ctx.Logger.Debug("found metav1 package", "package", metav1Pkg.PkgPath)
160+
}
161+
148162
// TODO: allow selecting a specific object
149163
kubeKinds := FindKubeKinds(parser, metav1Pkg)
150164
if len(kubeKinds) == 0 {
151165
// no objects in the roots
166+
if ctx.Logger != nil {
167+
ctx.Logger.Debug("no Kubernetes kinds found in packages")
168+
}
152169
return nil
153170
}
154171

172+
if ctx.Logger != nil {
173+
ctx.Logger.Info("found Kubernetes kinds for CRD generation", "count", len(kubeKinds))
174+
for _, kind := range kubeKinds {
175+
ctx.Logger.Debug("processing Kubernetes kind", "group", kind.Group, "kind", kind.Kind)
176+
}
177+
}
178+
155179
crdVersions := g.CRDVersions
156180

157181
if len(crdVersions) == 0 {
158182
crdVersions = []string{defaultVersion}
159183
}
160184

185+
if ctx.Logger != nil {
186+
ctx.Logger.Debug("using CRD versions", "versions", crdVersions)
187+
}
188+
161189
var headerText string
162190

163191
if g.HeaderFile != "" {
@@ -166,6 +194,9 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
166194
return err
167195
}
168196
headerText = string(headerBytes)
197+
if ctx.Logger != nil {
198+
ctx.Logger.Debug("loaded header file", "file", g.HeaderFile, "size", len(headerBytes))
199+
}
169200
}
170201
headerText = strings.ReplaceAll(headerText, " YEAR", " "+g.Year)
171202

@@ -178,6 +209,10 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
178209
}
179210

180211
for _, groupKind := range kubeKinds {
212+
if ctx.Logger != nil {
213+
ctx.Logger.Debug("generating CRD", "group", groupKind.Group, "kind", groupKind.Kind)
214+
}
215+
181216
parser.NeedCRDFor(groupKind, g.MaxDescLen)
182217
crdRaw := parser.CustomResourceDefinitions[groupKind]
183218
addAttribution(&crdRaw)
@@ -202,9 +237,18 @@ func (g Generator) Generate(ctx *genall.GenerationContext) error {
202237
} else {
203238
fileName = fmt.Sprintf("%s_%s.%s.yaml", crdRaw.Spec.Group, crdRaw.Spec.Names.Plural, crdVersions[i])
204239
}
240+
241+
if ctx.Logger != nil {
242+
ctx.Logger.Debug("writing CRD file", "filename", fileName, "group", groupKind.Group, "kind", groupKind.Kind)
243+
}
244+
205245
if err := ctx.WriteYAML(fileName, headerText, []interface{}{crd}, yamlOpts...); err != nil {
206246
return err
207247
}
248+
249+
if ctx.Logger != nil {
250+
ctx.Logger.Info("generated CRD", "filename", fileName, "group", groupKind.Group, "kind", groupKind.Kind)
251+
}
208252
}
209253
}
210254

pkg/genall/genall.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"encoding/json"
2121
"fmt"
2222
"io"
23+
"log/slog"
2324
"os"
2425

2526
"golang.org/x/tools/go/packages"
@@ -101,6 +102,8 @@ type Runtime struct {
101102
OutputRules OutputRules
102103
// ErrorWriter defines where to write error messages.
103104
ErrorWriter io.Writer
105+
// Verbose enables verbose logging for debugging purposes.
106+
Verbose bool
104107
}
105108

106109
// GenerationContext defines the common information needed for each Generator
@@ -117,6 +120,8 @@ type GenerationContext struct {
117120
// InputRule describes how to load associated boilerplate artifacts.
118121
// It should *not* be used to load source files.
119122
InputRule
123+
// Logger is the logger for verbose output. If nil, logging is disabled.
124+
Logger *slog.Logger
120125
}
121126

122127
// WriteYAMLOptions implements the Options Pattern for WriteYAML.
@@ -261,17 +266,31 @@ func (r *Runtime) Run() bool {
261266
return true
262267
}
263268

269+
// Set up logging based on verbose setting
270+
var logger *slog.Logger
271+
if r.Verbose {
272+
logger = slog.New(slog.NewTextHandler(r.ErrorWriter, &slog.HandlerOptions{
273+
Level: slog.LevelDebug,
274+
}))
275+
logger.Info("verbose logging enabled")
276+
}
277+
264278
hadErrs := false
265279
for _, gen := range r.Generators {
266280
ctx := r.GenerationContext // make a shallow copy
267281
ctx.OutputRule = r.OutputRules.ForGenerator(gen)
282+
ctx.Logger = logger
268283

269284
// don't pass a typechecker to generators that don't provide a filter
270285
// to avoid accidents
271286
if _, needsChecking := (*gen).(NeedsTypeChecking); !needsChecking {
272287
ctx.Checker = nil
273288
}
274289

290+
if logger != nil {
291+
logger.Debug("running generator", "generator", fmt.Sprintf("%T", *gen))
292+
}
293+
275294
if err := (*gen).Generate(&ctx); err != nil {
276295
fmt.Fprintln(r.ErrorWriter, err)
277296
hadErrs = true

pkg/genall/options.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626

2727
var (
2828
InputPathsMarker = markers.Must(markers.MakeDefinition("paths", markers.DescribesPackage, InputPaths(nil)))
29+
VerboseMarker = markers.Must(markers.MakeDefinition("verbose", markers.DescribesPackage, Verbose(false)))
2930
)
3031

3132
// +controllertools:marker:generateHelp:category=""
@@ -35,16 +36,30 @@ var (
3536
// Multiple paths can be specified using "{path1, path2, path3}".
3637
type InputPaths []string
3738

39+
// +controllertools:marker:generateHelp:category=""
40+
41+
// Verbose enables verbose/debug logging for generator operations.
42+
// When enabled, generators will output additional debug information
43+
// about their processing, which can help troubleshoot issues when
44+
// generators don't produce expected output.
45+
type Verbose bool
46+
3847
// RegisterOptionsMarkers registers "mandatory" options markers for FromOptions into the given registry.
39-
// At this point, that's just InputPaths.
48+
// At this point, that's just InputPaths and Verbose.
4049
func RegisterOptionsMarkers(into *markers.Registry) error {
4150
if err := into.Register(InputPathsMarker); err != nil {
4251
return err
4352
}
53+
if err := into.Register(VerboseMarker); err != nil {
54+
return err
55+
}
4456
// NB(directxman12): we make this optional so we don't have a bootstrap problem with helpgen
4557
if helpGiver, hasHelp := ((interface{})(InputPaths(nil))).(HasHelp); hasHelp {
4658
into.AddHelp(InputPathsMarker, helpGiver.Help())
4759
}
60+
if helpGiver, hasHelp := ((interface{})(Verbose(false))).(HasHelp); hasHelp {
61+
into.AddHelp(VerboseMarker, helpGiver.Help())
62+
}
4863
return nil
4964
}
5065

@@ -90,6 +105,9 @@ func FromOptionsWithConfig(cfg *packages.Config, optionsRegistry *markers.Regist
90105
return nil, err
91106
}
92107

108+
// Set verbose logging if enabled
109+
genRuntime.Verbose = protoRt.Verbose
110+
93111
// attempt to figure out what the user wants without a lot of verbose specificity:
94112
// if the user specifies a default rule, assume that they probably want to fall back
95113
// to that. Otherwise, assume that they just wanted to customize one option from the
@@ -117,6 +135,7 @@ func protoFromOptions(optionsRegistry *markers.Registry, options []string) (prot
117135
ByGenerator: make(map[*Generator]OutputRule),
118136
}
119137
var paths []string
138+
var verbose bool
120139

121140
// collect the generators first, so that we can key the output on the actual
122141
// generator, which matters if there's settings in the gen object and it's not a pointer.
@@ -156,6 +175,8 @@ func protoFromOptions(optionsRegistry *markers.Registry, options []string) (prot
156175
continue
157176
case InputPaths:
158177
paths = append(paths, val...)
178+
case Verbose:
179+
verbose = bool(val)
159180
default:
160181
return protoRuntime{}, fmt.Errorf("unknown option marker %q", defn.Name)
161182
}
@@ -176,6 +197,7 @@ func protoFromOptions(optionsRegistry *markers.Registry, options []string) (prot
176197
Generators: gens,
177198
OutputRules: rules,
178199
GeneratorsByName: gensByName,
200+
Verbose: verbose,
179201
}, nil
180202
}
181203

@@ -186,6 +208,7 @@ type protoRuntime struct {
186208
Generators Generators
187209
OutputRules OutputRules
188210
GeneratorsByName map[string]*Generator
211+
Verbose bool
189212
}
190213

191214
// splitOutputRuleOption splits a marker name of "output:rule:gen" or "output:rule"

pkg/genall/zz_generated.markerhelp.go

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)