Diagnostics (Pro)

Diagnostics is a single ledger of every attempt DefectDojo makes to talk to something outside itself — and of the attempts other systems make to talk to it. When a ticket never appeared, a scan never imported, or a user could not sign in, this is the page that says what happened, when, to which configuration, and who set it off.

Diagnostics is a DefectDojo Pro feature. Find it under Connect > Diagnostics.

The Diagnostics ledger, Errors view

What is recorded

One row is written per attempt, from every subsystem that reaches outside DefectDojo:

SourceWhat produces rows
ConnectorUpstream connector discover and sync runs
Downstream integratorPushes to Jira, GitHub, GitLab, ServiceNow, and the other downstream connectors
JiraThe legacy Jira integration: pushes, comments, and previews
SSO (OIDC/OAuth2)Sign-in attempts through an OAuth provider
SAMLSAML assertions, including signature and attribute failures
LDAPLDAP binds and lookups
Import / ReimportScan uploads, whether by UI, API, or schedule
Rules engineRule evaluations and the actions they attempt
SchedulingScheduled runs, including ones that never started
SenseiRepository scans and fix runs
NotificationOutbound notification delivery
SystemInstance-level activity that belongs to no product

Rows are written alongside the subsystem, never in place of it. Each adapter is attached to the origin record and is deliberately fail-safe: if writing a diagnostic row raises, the error is swallowed and the original operation carries on. Diagnostics can therefore never be the reason a push, import, or login fails.

Because rows are keyed on the record that produced them, re-saving an origin record updates its existing diagnostic row rather than adding a duplicate. One attempt is one row for its whole life, from Queued through Running to its outcome.

Fields on a row

FieldMeaning
WhenWhen the row was recorded; Started, Finished and Duration describe the attempt itself
SourceThe subsystem, from the table above
ProviderThe specific tool or provider within that source (jira, github, okta, a scanner name)
OperationWhat was attempted (push, sync, login, reimport, rule_run)
StatusQueued, Running, Success, Failed, Timed out, Skipped, or Dry run
SeverityInfo, Warning, Error, or Critical
SummaryA one-line outcome, safe to read at a glance
TriggerWhat set the attempt off: UI, API, Scheduled, Webhook, Automatic, Command line, or System
Triggered byThe user responsible, or System for unattended work
AssetThe product the attempt belongs to; empty means instance-level
Related objectThe finding, engagement, or other record the attempt was about
ConfigurationWhich configuration was used, by its label
External referenceThe identifier the other system returned, such as a created issue key
Correlation IDTies together rows from one logical operation
Reported detail and ContextThe full technical detail (restricted, see Who sees what)

The four views

The tabs above the table are saved starting points, not filters you have to rebuild:

  • Errors — failures and timeouts. The one to open first.
  • Successes — proof that a working integration is working, useful when someone reports “nothing is syncing”.
  • Never completed — attempts still Queued or Running well past when they should have finished. These are the silent ones: nothing failed, so nothing was reported, but nothing arrived either.
  • All events — everything, unfiltered.

All events, showing every source

The active view is part of the page URL, so a view is linkable and survives a refresh.

Narrowing the list

  • Time range — 24 hours, 7 days, 30 days, or 90 days, from the buttons in the header.
  • Source counts — the coloured counts under the summary cards are also quick filters. Click one to show only that source; click it again (or Clear source filter) to go back. One or none is active at a time.
  • Per-column filters and sorting — every column filters and sorts, including Severity and Source. Severity sorts by seriousness (Critical → Info) rather than alphabetically, and Source sorts by the label you see rather than the value stored underneath.
  • Keyword Search — searches across the text fields at once.
  • Column preferences — the column picker and its saved layouts behave as they do on every other Pro list.

A source count used as a quick filter

Click the magnifier at the start of a row to open the whole attempt:

A single event, including the redaction notice

Credentials are removed before the row is written

Integration errors quote the request that failed, and those quotes carry secrets: an Authorization header, a token in a query string, a password inside a connection URL. Diagnostics strips them on the way in, so the original value never reaches the database and no later change of mind can expose it.

Two things are scrubbed:

  • Values under credential-shaped keys — anything whose key looks like a secret (password, token, secret, api_key, authorization, private_key, and similar, in any capitalisation or with dashes or spaces). A small set of keys is exempt because only their presence matters, never their content.
  • Values that look like credentials wherever they appear — bearer and basic authorization headers, JWTs, credentials embedded in URLs (https://user:pass@host), recognisable vendor token prefixes, and PEM blocks.

Each is replaced with [redacted]. The surrounding message is kept, so the error stays readable:

401 Unauthorized: Authorization: [redacted]
upload rejected: https://svc:[redacted]@sftp.example/out/…

Long values are truncated, and deeply nested context is flattened, so one enormous payload cannot bloat the table.

When anything was removed from a row, the row says so, rather than leaving you to wonder whether the field was empty or emptied.

Redaction is best-effort by design. The scrubber recognises credential shapes. A secret that looks like ordinary prose, under a key that does not read as sensitive, can still be recorded. Treat Diagnostics as an operational log, not as a place secrets are guaranteed to be absent — and keep the technical detail restricted to the people who need it.

Who sees what

Diagnostics is tiered, because the summary of a failure is useful to a product owner while the raw request behind it is not.

SuperuserEveryone else
Rows for products they are authorized onYesYes
Instance-level rows (no product)YesNo
Summary, source, status, severity, timings, configurationYesYes
Reported detail, Context, Remote IPYesWithheld, and labelled as withheld

A non-superuser sees that a detail exists and is being withheld, rather than an empty field that reads like missing data. Instance-level rows — SSO, SAML, LDAP, and other activity that belongs to no product — are superuser-only, since there is no product membership that could grant access to them.

How long records are kept

A scheduled task trims the ledger so it cannot grow without limit:

SeverityKept for
Info30 days
Warning, Error, Critical180 days

Both windows are configurable with the DIAGNOSTIC_EVENT_INFO_RETENTION_DAYS and DIAGNOSTIC_EVENT_RETENTION_DAYS settings. Deletion runs in batches, so a large purge does not hold a long transaction open.

API

The ledger is read-only over the API, at /api/v2/diagnostic_events/:

EndpointReturns
GET /api/v2/diagnostic_events/The list, with the filters below
GET /api/v2/diagnostic_events/{id}/One event
GET /api/v2/diagnostic_events/summary/The counts behind the header cards, including the per-source tallies
GET /api/v2/diagnostic_events/choices/The valid values for source, status, severity, and trigger

Useful parameters:

ParameterEffect
source, status, severity, triggerAccept several comma-separated values at once
failures_only=trueFailures and timeouts
unresolved_only=trueAttempts still queued or running
product_nameFilter by product name
object_modelFilter by the kind of record the attempt was about
o=Ordering, prefixed with - to reverse (o=-created_at)

The same access rules apply: a non-superuser gets product-scoped rows with the restricted fields withheld.

Working out what went wrong

  • A ticket never appeared. Filter Source to the integrator (or Jira), then read Status. Failed gives you the reason in Summary; Queued well after the fact means the job never ran, which is a worker or scheduling problem rather than a credential one.
  • A user cannot sign in. Filter Source to SSO, SAML, or LDAP, and read the failure for their attempt — a bad assertion signature, a rejected bind, a mismatched attribute. These rows are instance-level, so they are superuser-only.
  • A scan did not show up. Filter Source to Import / Reimport. Look at Trigger to tell an unattended scheduled upload from someone’s manual one, and at Triggered by for who to ask.
  • Something is retrying forever. Sort by Correlation ID, or filter to one, to see every attempt of the same logical operation together.
  • “Nothing is working.” Open Successes for the same window first. A healthy list there turns a vague outage into a specific one.