Verbosity Levels

Why progressive verbosity? Developers want different levels of detail at different times. Simple mental model: more v's = more info. LLMs can use higher verbosity for better context.

Progressive verbosity pattern for QNTX CLI commands using the -v flag.

Pattern

qntx <command>        # Level 0 (default) - Results and errors only
qntx <command> -v     # Level 1 - Progress, startup, plugin status
qntx <command> -vv    # Level 2 - Queries, timing, config details
qntx <command> -vvv   # Level 3 - Plugin logs, SQL, gRPC calls
qntx <command> -vvvv  # Level 4 - Full request/response bodies

Output Categories

Verbosity controls what categories of output are shown, not just log severity. The system uses semantic output categories defined in logger/output.go.

Category Reference

CategoryLevelDescription
Results, Errors0Final results and critical errors (always shown)
Progress1Startup messages, plugin status, progress updates
Ax AST1Parsed query AST for Ax queries
Plugin Status1Plugin load/unload notifications
Ax Matches2What attestations matched the query
Timing2Operation timing (opt-in, auto-shown if slow)
Config2Configuration details
Plugin Stdout3Standard output from plugins
Plugin Stderr3Standard error from plugins
SQL Queries4Raw SQL queries executed
gRPC Calls4gRPC method calls
Full Payloads4Complete request/response bodies

Special Behaviors

Timing with Slow Threshold

Timing information has special handling via logger.ShouldShowTiming():

if logger.ShouldShowTiming(verbosity, durationMS) {
    fmt.Printf("Operation took %dms\n", durationMS)
}

Zero Value Filtering

Zero and default values add noise at lower verbosity levels. They're only shown at level 4 (-vvvv) where confirming "this is actually zero" matters for full data dumps.

Filtered at levels 0-3:

Only shown at level 4: All values including zeros for complete data dumps.

// Only log non-zero counts at lower verbosity
if count > 0 || logger.ShouldShowZeroInt(verbosity) {
    log.Infow("Processed items", "count", count)
}

// Only log if value differs from default
if status != "unknown" || logger.ShouldShowDefaultValue(verbosity) {
    log.Infow("Status check", "status", status)
}

Ax Query Output

Ax queries have granular output control:

Implementation

Checking Output Categories

Use logger.ShouldOutput() to check if output should be shown:

import "github.com/teranos/QNTX/logger"

func executeQuery(verbosity int, query string) {
    // Level 1+: Show parsed AST
    if logger.ShouldOutput(verbosity, logger.OutputAxAST) {
        fmt.Printf("Parsed AST: %v\n", ast)
    }

    // Level 2+: Show what matched
    if logger.ShouldOutput(verbosity, logger.OutputAxMatches) {
        fmt.Printf("Matched %d attestations\n", len(matches))
    }

    // Level 4+: Show raw SQL
    if logger.ShouldOutput(verbosity, logger.OutputSQLQueries) {
        fmt.Printf("SQL: %s\n", sqlQuery)
    }
}

Logger Level Mapping

Verbosity also maps to zap log levels via logger.VerbosityToLevel():

VerbosityLog Level
0 (none)WarnLevel
1 (-v)InfoLevel
2+ (-vv)DebugLevel

Symbol-Aware Logging

Use structured symbol logging instead of embedding symbols in messages:

// Instead of:
logger.Infow(sym.Pulse + " Job started", "job_id", id)

// Use:
logger.PulseInfow("Job started", "job_id", id)

// Or with instance loggers:
pulseLog := logger.AddPulseSymbol(s.logger)
pulseLog.Infow("Job started", "job_id", id)

This keeps log messages clean and makes symbols queryable as structured fields.

Level Definitions

Level 0 (Default)

Clean, user-facing output only:

Hides parsing details, internal processing, SQL queries, and debug information.

Level 1 (-v)

Progress and status information:

Level 2 (-vv)

Debug information for troubleshooting:

Level 3 (-vvv)

Deep debugging context:

Level 4 (-vvvv)

Ultra-verbose troubleshooting:

ax Command Examples

Level 0 (Default)

Subject: "user_123"
Predicate: "has_skill"
Object: "Go"

1 attestation found

Level 1 (-v)

Parsing query...
  Subject: "user_123"
  Predicate: "has_skill"
  Object: "Go"
  Context: (none)

Executing query...
Found 1 matching attestation

Results:
  [attestation details...]

Level 2 (-vv)

Parsing query...
  Subject: "user_123"
  Predicate: "has_skill"
  Object: "Go"

Matched attestations:
  - ats_123abc... (created 2024-01-15)

Execution time: 2.3ms

Results with full context:
  [Complete attestation data with metadata...]

Level 4 (-vvvv)

[All Level 2 output plus:]

SQL: SELECT * FROM attestations WHERE subject = ? AND predicate = ? AND object = ?
Parameters: ["user_123", "has_skill", "Go"]

Implementation Notes

The verbosity flag is defined globally in the root command and available to all subcommands. Commands interpret levels based on their specific needs while following the general pattern above.

See logger/output.go for the complete list of output categories and their verbosity requirements.