Skip to content

Commit b4d9ea8

Browse files
authored
feat: add performance stats (#202)
1 parent 38397b6 commit b4d9ea8

File tree

11 files changed

+967
-56
lines changed

11 files changed

+967
-56
lines changed

.github/workflows/scheduled-jobs.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ jobs:
6464
env:
6565
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
6666

67+
- name: Save performance log
68+
uses: actions/upload-artifact@v4
69+
with:
70+
name: performance.log
71+
path: build/ephemeral/performance.log
72+
retention-days: 14
73+
6774
- uses: actions/checkout@v6
6875
with:
6976
repository: datreeio/CRDs-catalog

internal/command/updater.go

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/CustomResourceDefinition/catalog/internal/crd"
1414
"github.com/CustomResourceDefinition/catalog/internal/generator"
1515
"github.com/CustomResourceDefinition/catalog/internal/registry"
16+
"github.com/CustomResourceDefinition/catalog/internal/timing"
1617
)
1718

1819
type Updater struct {
@@ -22,16 +23,18 @@ type Updater struct {
2223
reader crd.CrdReader
2324
registry *registry.SourceRegistry
2425
registryPath string
26+
performanceLog string
2527
}
2628

27-
func NewUpdater(configuration, schema, definitions, registryPath string, logger io.Writer, flags *flag.FlagSet) Updater {
29+
func NewUpdater(configuration, schema, definitions, registryPath, performancePath string, logger io.Writer, flags *flag.FlagSet) Updater {
2830
return Updater{
29-
flags: flags,
30-
Configuration: configuration,
31-
Schema: schema,
32-
Definitions: definitions,
33-
registryPath: registryPath,
34-
Logger: logger,
31+
flags: flags,
32+
Configuration: configuration,
33+
Schema: schema,
34+
Definitions: definitions,
35+
registryPath: registryPath,
36+
Logger: logger,
37+
performanceLog: performancePath,
3538
}
3639
}
3740

@@ -68,6 +71,13 @@ func (cmd Updater) Run() error {
6871
}
6972
defer os.RemoveAll(tmpDir)
7073

74+
totalStats := timing.NewStats()
75+
76+
if err := totalStats.OpenLogFile(cmd.performanceLog); err != nil {
77+
return fmt.Errorf("failed to open performance log: %w", err)
78+
}
79+
defer totalStats.CloseLogFile()
80+
7181
for _, config := range splitConfigurations(configurations) {
7282
runtime.GC()
7383

@@ -82,6 +92,11 @@ func (cmd Updater) Run() error {
8292
fmt.Fprintf(cmd.Logger, "::warning:: build of %s failed: %v\n", config.Name, err)
8393
continue
8494
}
95+
96+
stats := build.Stats()
97+
for _, op := range stats.GetAllStats() {
98+
totalStats.Record(op.Category, op.Type, op.Name, op.Duration, op.Success, op.StartTime)
99+
}
85100
}
86101

87102
if cmd.registry != nil && cmd.registryPath != "" {
@@ -90,6 +105,8 @@ func (cmd Updater) Run() error {
90105
}
91106
}
92107

108+
totalStats.PrintSummary(cmd.Logger)
109+
93110
return merge(tmpDir, cmd.Schema)
94111
}
95112

internal/command/updater_test.go

Lines changed: 132 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func TestRun(t *testing.T) {
1717
server, config, tmpDir := setup(t)
1818
defer server.Close()
1919

20-
updater := NewUpdater(config, tmpDir, tmpDir, "", bytes.NewBuffer([]byte{}), nil)
20+
updater := NewUpdater(config, tmpDir, tmpDir, "", "", bytes.NewBuffer([]byte{}), nil)
2121

2222
err := updater.Run()
2323
assert.Nil(t, err)
@@ -221,7 +221,7 @@ func TestRunWithRegistryLoadError(t *testing.T) {
221221
registryPath := path.Join(tmpDir, "registry.yaml")
222222
os.WriteFile(registryPath, []byte("invalid: yaml: content:"), 0644)
223223

224-
updater := NewUpdater(unused, tmpDir, tmpDir, registryPath, bytes.NewBuffer([]byte{}), nil)
224+
updater := NewUpdater(unused, tmpDir, tmpDir, registryPath, "", bytes.NewBuffer([]byte{}), nil)
225225

226226
err := updater.Run()
227227
assert.NotNil(t, err)
@@ -236,7 +236,7 @@ func TestRunWithRegistrySavesUpdates(t *testing.T) {
236236
initialContent := "sources: {}\n"
237237
os.WriteFile(registryPath, []byte(initialContent), 0664)
238238

239-
updater := NewUpdater(config, tmpDir, tmpDir, registryPath, bytes.NewBuffer([]byte{}), nil)
239+
updater := NewUpdater(config, tmpDir, tmpDir, registryPath, "", bytes.NewBuffer([]byte{}), nil)
240240

241241
err := updater.Run()
242242
assert.Nil(t, err)
@@ -269,7 +269,7 @@ func TestRunWithRegistryRemovesStaleEntries(t *testing.T) {
269269
`
270270
os.WriteFile(registryPath, []byte(initialContent), 0664)
271271

272-
updater := NewUpdater(config, tmpDir, tmpDir, registryPath, bytes.NewBuffer([]byte{}), nil)
272+
updater := NewUpdater(config, tmpDir, tmpDir, registryPath, "", bytes.NewBuffer([]byte{}), nil)
273273

274274
err := updater.Run()
275275
assert.Nil(t, err)
@@ -287,9 +287,136 @@ func TestRunWithRegistryRemovesStaleEntries(t *testing.T) {
287287
func TestCheckLocal(t *testing.T) {
288288
output := "../../build/ephemeral/schema"
289289
config := "../../build/configuration.yaml"
290-
updater := NewUpdater(config, output, output, "", nil, nil)
290+
updater := NewUpdater(config, output, output, "", "", nil, nil)
291291

292292
err := updater.Run()
293293
assert.Nil(t, err)
294294
assert.True(t, false, "this test should always be skipped and/or ignored")
295295
}
296+
297+
func TestRunAggregatesStats(t *testing.T) {
298+
b, err := os.ReadFile("testdata/updater/multiple.yaml")
299+
assert.Nil(t, err)
300+
301+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
302+
w.WriteHeader(http.StatusOK)
303+
w.Write(b)
304+
}))
305+
defer server.Close()
306+
307+
template := `
308+
- apiGroups:
309+
- chart.uri
310+
crds:
311+
- baseUri: {{ server }}
312+
paths:
313+
- chart-1.0.0.yaml
314+
version: 1.0.0
315+
kind: http
316+
name: http
317+
`
318+
tmpDir := t.TempDir()
319+
320+
config := path.Join(tmpDir, "config.yaml")
321+
os.WriteFile(config, []byte(strings.ReplaceAll(template, "{{ server }}", server.URL)), 0664)
322+
323+
output := bytes.NewBuffer([]byte{})
324+
updater := NewUpdater(config, tmpDir, tmpDir, "", "", output, nil)
325+
326+
err = updater.Run()
327+
assert.Nil(t, err)
328+
329+
outStr := output.String()
330+
assert.Contains(t, outStr, "Update Statistics")
331+
assert.Contains(t, outStr, "Overall:")
332+
assert.Contains(t, outStr, "operations")
333+
assert.Contains(t, outStr, "Http:")
334+
assert.Contains(t, outStr, "api_fetch")
335+
}
336+
337+
func TestRunWithMultipleConfigsAggregatesStats(t *testing.T) {
338+
b, err := os.ReadFile("testdata/updater/multiple.yaml")
339+
assert.Nil(t, err)
340+
341+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
342+
w.WriteHeader(http.StatusOK)
343+
w.Write(b)
344+
}))
345+
defer server.Close()
346+
347+
template := `
348+
- apiGroups:
349+
- chart.uri
350+
crds:
351+
- baseUri: {{ server }}
352+
paths:
353+
- chart-1.0.0.yaml
354+
version: 1.0.0
355+
kind: http
356+
name: http1
357+
- apiGroups:
358+
- chart.uri
359+
crds:
360+
- baseUri: {{ server }}
361+
paths:
362+
- chart-1.0.0.yaml
363+
version: 1.0.0
364+
kind: http
365+
name: http2
366+
`
367+
tmpDir := t.TempDir()
368+
369+
config := path.Join(tmpDir, "config.yaml")
370+
os.WriteFile(config, []byte(strings.ReplaceAll(template, "{{ server }}", server.URL)), 0664)
371+
372+
output := bytes.NewBuffer([]byte{})
373+
updater := NewUpdater(config, tmpDir, tmpDir, "", "", output, nil)
374+
375+
err = updater.Run()
376+
assert.Nil(t, err)
377+
378+
outStr := output.String()
379+
assert.Contains(t, outStr, "Overall:")
380+
assert.Contains(t, outStr, "api_fetch")
381+
}
382+
383+
func TestRunWithPerformanceLog(t *testing.T) {
384+
b, err := os.ReadFile("testdata/updater/multiple.yaml")
385+
assert.Nil(t, err)
386+
387+
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
388+
w.WriteHeader(http.StatusOK)
389+
w.Write(b)
390+
}))
391+
defer server.Close()
392+
393+
template := `
394+
- apiGroups:
395+
- chart.uri
396+
crds:
397+
- baseUri: {{ server }}
398+
paths:
399+
- chart-1.0.0.yaml
400+
version: 1.0.0
401+
kind: http
402+
name: http
403+
`
404+
tmpDir := t.TempDir()
405+
406+
config := path.Join(tmpDir, "config.yaml")
407+
os.WriteFile(config, []byte(strings.ReplaceAll(template, "{{ server }}", server.URL)), 0664)
408+
409+
logPath := path.Join(tmpDir, "perf.log")
410+
411+
output := bytes.NewBuffer([]byte{})
412+
updater := NewUpdater(config, tmpDir, tmpDir, "", logPath, output, nil)
413+
414+
err = updater.Run()
415+
assert.Nil(t, err)
416+
417+
perfContent, err := os.ReadFile(logPath)
418+
assert.Nil(t, err)
419+
assert.NotEmpty(t, string(perfContent))
420+
assert.Contains(t, string(perfContent), "http")
421+
assert.Contains(t, string(perfContent), "api_fetch")
422+
}

0 commit comments

Comments
 (0)