How to Debug PDF Classification with RUST_LOG in pdf-inspector
Set the RUST_LOG environment variable to enable structured debug output for any module in the pdf-inspector Rust codebase, with logs written to stderr to preserve normal program output.
The pdf-inspector repository from Firecrawl uses the log crate combined with env_logger to provide deep visibility into its PDF classification pipeline. When you need to understand why a page was classified as TextBased, Scanned, ImageBased, or Mixed, structured logging lets you inspect the intermediate values driving every decision.
How RUST_LOG Works in pdf-inspector
The logging system follows the standard env_logger pattern: module_path=level. Each major component contains log::debug! and log::trace! statements that report operator counts, font metadata, layout heuristics, and detection thresholds.
Key modules and their paths:
pdf_inspector::detector— core classification logic insrc/detector.rspdf_inspector::extractor::layout— column detection and reading-order logic insrc/extractor/layout.rspdf_inspector::tables— table detection strategies insrc/tables/mod.rspdf_inspector::markdown::analysis— paragraph threshold calculations insrc/markdown/analysis.rspdf_inspector::extractor::content_stream— raw content-stream operator analysispdf_inspector::extractor::fonts— font metadata and CMap parsing
Logs emit to stderr, so piping stdout to /dev/null or a file keeps your Markdown or JSON output clean.
Common RUST_LOG Patterns for PDF Classification Debugging
Inspect the PDF Type Detector
To see why a document was classified as scanned or mixed:
RUST_LOG=pdf_inspector::detector=debug cargo run --release --bin detect-pdf -- file.pdf
This activates debug statements in src/detector.rs that print per-page analysis values.
Debug Content-Stream Operators
For the lowest-level view of operator counts that determine if a page has extractable text:
RUST_LOG=pdf_inspector::extractor::content_stream=trace cargo run --bin pdf2md -- file.pdf > /dev/null
Use trace level for maximum verbosity on text operations.
Analyze Font and Encoding Issues
When characters decode incorrectly or ligatures fail:
RUST_LOG=pdf_inspector::extractor::fonts=debug cargo run --bin pdf2md -- file.pdf > /dev/null
This reveals CMap parsing decisions and ToUnicode mapping problems in the font extraction pipeline.
Examine Column and Reading-Order Logic
For newspaper-style layouts or multi-column documents:
RUST_LOG=pdf_inspector::extractor::layout=debug cargo run --bin pdf2md -- file.pdf > /dev/null
The src/extractor/layout.rs module logs histogram valleys and derived column counts.
Trace Table Detection
To follow the three detection strategies (rect-based, line-based, heuristic):
RUST_LOG=pdf_inspector::tables=debug cargo run --bin pdf2md -- file.pdf > /dev/null
Monitor Paragraph Threshold Analysis
For debugging Y-gap heuristics that segment text into paragraphs:
RUST_LOG=pdf_inspector::markdown::analysis=debug cargo run --bin pdf2md -- file.pdf > /dev/null
Enable All Debug Output
For comprehensive tracing across all modules:
RUST_LOG=pdf_inspector=debug cargo run --bin pdf2md -- file.pdf > /dev/null
Combine Multiple Modules
Use comma-separated filters for focused cross-module debugging:
RUST_LOG=pdf_inspector::detector=debug,pdf_inspector::tables=debug cargo run --bin pdf2md -- file.pdf
Interpreting Debug Output
When detector logging is active, you'll see structured entries like:
DEBUG pdf_inspector::detector::detect_from_document: page 3: text_ops=12 images=1 image_count=1 template=0 unique_chars=27 alphanum=5 path_ops=0 vector_text=false image_area=0 identity_h_no_tounicode=false type3_only=false font_changes=3 decodable_fonts=true
These fields map directly to the PageAnalysis struct in src/detector.rs. Use them to answer specific classification questions:
- Why scanned? — Check
text_opsbelow threshold,images>= 1, and lowalphanumcount - Why mixed requiring OCR? — Look for
has_template_imageorhas_vector_textflags - Why wrong column count? — Check
pdf_inspector::extractor::layoutlogs for valley detection and early-exit conditions
Filtering Output with Grep
Pipe stderr to narrow results:
RUST_LOG=pdf_inspector::detector=debug cargo run --release --bin detect-pdf -- file.pdf 2>&1 | grep "pages with text"
This pattern isolates specific metrics without drowning in trace-level noise.
Key Source Files for Debugging
| File | Module Path | Purpose |
|---|---|---|
src/detector.rs |
pdf_inspector::detector |
PDF type detection and OCR recommendations |
src/extractor/layout.rs |
pdf_inspector::extractor::layout |
Column detection and reading-order heuristics |
src/tables/mod.rs |
pdf_inspector::tables |
Table detection pipeline |
src/markdown/analysis.rs |
pdf_inspector::markdown::analysis |
Paragraph-gap analysis |
src/tounicode.rs |
pdf_inspector::tounicode |
CMap and ToUnicode parsing logs |
For quick reference, see docs/debugging.md and AGENTS.md in the repository root.
Summary
- Set
RUST_LOGwith module path and level to activate specific debug output - Use
debugfor operational metrics,tracefor exhaustive operator-level detail - Pipe stdout to isolate logs when generating Markdown or JSON output
- Read field names in log output against
PageAnalysisinsrc/detector.rsto trace classification decisions - Combine modules with comma-separated filters for cross-cutting investigations
Frequently Asked Questions
What log levels does pdf-inspector support?
The env_logger backend recognizes error, warn, info, debug, and trace. For PDF classification debugging, use debug for summary metrics and trace for raw operator counts. The default level is error when RUST_LOG is unset.
How do I debug why a page was incorrectly marked as scanned?
Set RUST_LOG=pdf_inspector::detector=debug and examine the text_ops, images, and alphanum fields. A page becomes Scanned when text_ops falls below min_text_ops_per_page (default 3) while containing images with insufficient alphanumeric characters.
Can I log to a file instead of stderr?
Redirect stderr in your shell: RUST_LOG=pdf_inspector=debug cargo run ... 2> debug.log. The env_logger configuration in pdf-inspector does not include file appenders, so shell redirection is the standard approach.
Where are the threshold constants defined?
Detection thresholds live in src/detector.rs as const values within the detection logic. Debug output shows the computed values compared against these thresholds, letting you identify which constraint triggered a classification without reading source code.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →