Reporting and profiling
How to produce reports and feed data into them. To read a failing report as an agent (the jq failure-diagnosis workflow), see ginkgo:debugging-failures. Docs: https://onsi.github.io/ginkgo/#generating-machine-readable-reports and https://onsi.github.io/ginkgo/#attaching-data-to-reports.
Console output
| Flag | Effect |
|---|---|
--succinct |
Minimal (default when running multiple suites). |
| (none) | Normal — detail only for failed specs (default, single suite). |
-v |
Full timeline for every spec; streams live in series. |
-vv |
-v plus node > Enter/< Exit events and every failure (not just the primary). |
--trace |
Full stack trace on every failure, not just panics. |
--no-color / GINKGO_NO_COLOR=TRUE |
Disable color. |
--github-output |
Format console output for GitHub Actions. |
In parallel (-p), -v/-vv timelines can't stream — the streams would interleave, so Ginkgo emits each spec's full timeline after that spec completes. → CI flags in ginkgo:ci.
Machine-readable reports
ginkgo -r --json-report=report.json --output-dir=./.reports
--json-reportis native and richest — an array oftypes.Report, each withSpecReports[]oftypes.SpecReport(godoc); build tooling against thetypespackage.--junit-report=x.xml,--teamcity-report=x,--gojson-report=x.go.jsonexist for external CI but lose Ginkgo metadata — use them to feed a system, not to diagnose. (JUnit maps aLabel("owner:XYZ")to theOwnerattribute.)--output-dir=DIRcollects all files in one place; under-rall suites merge into one report file.--keep-separate-reportswrites onePACKAGE_report.jsonper package instead.- Every machine-readable report embeds the full
-vvtimeline regardless of console verbosity. Run the suite quiet and mine the file — you don't need-vvon the console to get rich detail in the report.
Programmatic reporting nodes
CurrentSpecReport() works in any run-phase closure — use it for in-spec conditional diagnostics:
AfterEach(func() {
if CurrentSpecReport().Failed() {
GinkgoWriter.Println(libraryClient.DebugLogs()) // expensive diagnostics, only on failure
}
})
For custom report files, don't roll your own in AfterEach — use reporting nodes:
ReportAfterEach(func(r SpecReport){...})/ReportBeforeEach— run for every spec including skipped/pending (unlikeAfterEach), after allAfterEaches. A failure here fails the spec. In parallel they run on each process concurrently — never write a shared file from them (you'll get interleaved garbage).ReportBeforeSuite/ReportAfterSuite("name", func(r Report){...})— top-level, and run only on process #1.ReportAfterSuitereceives theReportaggregated across all parallel processes — this is the safe place for custom suite-level report files:
ReportAfterSuite("custom report", func(report Report) {
f, _ := os.Create("report.custom")
for _, sr := range report.SpecReports {
fmt.Fprintf(f, "%s | %s\n", sr.FullText(), sr.State)
}
f.Close()
})
Reporting nodes can be made interruptible by also accepting SpecContext → ginkgo:timeouts-and-async.
Attaching data to a spec: AddReportEntry
It("is reported", func() {
AddReportEntry("Publish stats", stats, ReportEntryVisibilityFailureOrVerbose)
})
AddReportEntry(name, value, ...args) attaches arbitrary data to the current spec; it lands in SpecReport.ReportEntries, in all machine-readable reports, and (per visibility) on the console. Visibility enum:
ReportEntryVisibilityAlways(default) — always printed.ReportEntryVisibilityFailureOrVerbose— only on failure or-v(likeGinkgoWriter).ReportEntryVisibilityNever— never on console, but still in the JSON report.
value is JSON-round-tripped into the report (retrieve via entry.GetRawValue() / json.Unmarshal(entry.Value.AsJSON, ...)). A fmt.Stringer/types.ColorableStringer controls console rendering; pass a pointer to capture later mutations. AddReportEntry decorators (Offset, CodeLocation, ReportEntryVisibility) → ginkgo:decorators.
Recap (owned by ginkgo:writing-specs): GinkgoWriter buffers log output and only prints it on failure (or always under -v); By("step") annotates the timeline. Use these for ad-hoc logging; use AddReportEntry for structured data you want in the report file.
Profiling
ginkgo -r --cover --coverpkg=./... --race --cpuprofile=cpu.out --output-dir=./.profiles
- Coverage:
--cover,--coverprofile=NAME(filename only — use--output-dirfor a path),--coverpkg=./...to cover beyond the suite's own package,--keep-separate-coverprofilesper-package.--raceforces--covermode=atomic. - Profiles:
--cpuprofile/--memprofile/--blockprofile/--mutexprofile(Ginkgo keeps the test binary so you cango tool pprof BINARY PROFILE).--output-dircollects and package-namespaces all profile/coverage assets. - Focused specs break profiling. A suite with
Focus/FIt/FDescribeexits early with a non-zero code, which stopsgo testfrom writing the profile. Subset with filters (--focus=,--label-filter=), notFocus→ginkgo:filtering.
See also
- Reading a failing report (
jqfilters, the panicked-vs-failed trap) →ginkgo:debugging-failures - The full CI flag set and version-matching →
ginkgo:ci - Decorators (
Label,ReportEntryVisibility,Offset) →ginkgo:decorators