tutorial

Monitoring Apache PDFBox with Vigilmon

Apache PDFBox services that generate, render, or extract PDF content — when the PDF rendering worker stalls, heap exhaustion causes silent truncation, or a malformed PDF hangs the extraction pipeline, downstream systems receive corrupted or incomplete documents. Here's how to monitor Apache PDFBox-based services, processing queues, and document generation endpoints with Vigilmon.

Apache PDFBox is a Java library for creating, rendering, and manipulating PDF documents — it provides APIs for generating PDFs from scratch, extracting text and images, merging and splitting documents, digitally signing PDFs, and rendering PDF pages to images. PDFBox is embedded in document processing pipelines, report generation services, invoice rendering systems, and archival workflows across finance, healthcare, legal, and publishing industries. When the PDF processing service runs out of heap due to a large document, a malformed PDF triggers an infinite loop in the parser, or the font rendering subsystem encounters a missing font and silently produces blank pages, the service continues accepting requests while delivering broken documents. Vigilmon provides external monitoring for PDFBox-based services, processing queue depths, document generation endpoints, and worker health so you detect PDF pipeline degradation before your users receive corrupted or empty documents.

What You'll Set Up

  • PDF generation endpoint availability monitoring
  • Document processing worker health checks
  • PDF extraction service response validation
  • Processing queue depth monitoring
  • JVM heap and GC pressure checks for PDFBox workers

Prerequisites

  • A PDFBox-based service exposing an HTTP endpoint (REST API, servlet, or Spring Boot application)
  • Access to application logs or JVM metrics (JMX or Actuator)
  • A free Vigilmon account

Step 1: Monitor the PDF Service HTTP Endpoint

PDFBox is typically embedded in a larger application — a Spring Boot service, a Jakarta EE application, or a standalone REST API. The application's health endpoint provides the first availability signal. When the JVM crashes, the application server runs out of threads, or a full GC cycle freezes the process, the HTTP endpoint stops responding. Set up a basic availability monitor:

  1. In Vigilmon, click Add MonitorHTTP/HTTPS.
  2. Set the URL to your PDF service's health endpoint (e.g., http://pdfservice.internal:8080/health or http://pdfservice.internal:8080/actuator/health).
  3. Set Check interval to 1 minute.
  4. Under Expected response, add keyword UP — Spring Boot Actuator health returns {"status":"UP"} when healthy.
  5. Set Timeout to 15 seconds.

For a Spring Boot Actuator health endpoint, verify the response structure:

# Verify PDF service health endpoint
PDF_SERVICE="http://pdfservice.internal:8080"

HEALTH_RESPONSE=$(curl -sf \
  --max-time 15 \
  -H "Accept: application/json" \
  "${PDF_SERVICE}/actuator/health" 2>/dev/null)

if echo "$HEALTH_RESPONSE" | python3 -c "
import sys, json
try:
    data = json.load(sys.stdin)
    status = data.get('status', '')
    sys.exit(0 if status == 'UP' else 1)
except:
    sys.exit(1)
" 2>/dev/null; then
  echo "PDF service health endpoint: UP"
  curl -s "https://vigilmon.online/heartbeat/REPLACE_WITH_YOUR_TOKEN"
else
  echo "PDF service health endpoint: DOWN or degraded"
  exit 1
fi

Step 2: Monitor PDF Generation End-to-End

An HTTP health check confirms the service is running but not that PDFBox is successfully generating documents. A large document request, a corrupted embedded font, or a PDFBox rendering bug can cause the generation endpoint to hang or return a zero-byte PDF without returning an HTTP error. Set up a synthetic document generation check:

  1. In Vigilmon, click Add MonitorCron Heartbeat.
  2. Set Expected ping interval to 5 minutes.
  3. Copy the heartbeat URL (e.g., https://vigilmon.online/heartbeat/abc123).

Create the PDF generation health check:

#!/bin/bash
# /usr/local/bin/pdfbox-generation-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/abc123"
PDF_SERVICE="http://pdfservice.internal:8080"
TIMEOUT=45
MIN_PDF_SIZE=500  # bytes — a valid single-page PDF is always larger than 500 bytes

# Request a test PDF document from the service
# Adjust the endpoint and payload to match your service's API
TEMP_PDF=$(mktemp /tmp/pdfcheck-XXXXXX.pdf)

HTTP_CODE=$(curl -sf \
  --max-time "$TIMEOUT" \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Accept: application/pdf" \
  -d '{"template": "health-check", "content": "monitoring test"}' \
  -o "$TEMP_PDF" \
  -w "%{http_code}" \
  "${PDF_SERVICE}/api/pdf/generate" 2>/dev/null)

PDF_SIZE=$(stat -c%s "$TEMP_PDF" 2>/dev/null || echo "0")
rm -f "$TEMP_PDF"

if [ "$HTTP_CODE" = "200" ] && [ "$PDF_SIZE" -ge "$MIN_PDF_SIZE" ]; then
  echo "PDF generation healthy: HTTP ${HTTP_CODE}, size ${PDF_SIZE} bytes"
  curl -s "$HEARTBEAT_URL"
else
  echo "PDF generation failed: HTTP ${HTTP_CODE}, size ${PDF_SIZE} bytes"
  exit 1
fi

Install the cron job:

chmod +x /usr/local/bin/pdfbox-generation-check.sh
(crontab -l 2>/dev/null; echo "*/5 * * * * /usr/local/bin/pdfbox-generation-check.sh >> /var/log/pdfbox-health.log 2>&1") | crontab -

The minimum size check (MIN_PDF_SIZE) catches silent truncation — PDFBox occasionally writes incomplete PDFs when interrupted mid-write, and the resulting file has a valid %PDF- header but no pages.


Step 3: Monitor PDF Text Extraction

PDFBox's text extraction pipeline (PDFTextStripper) is a separate execution path from PDF generation and can fail independently. A corrupt or password-protected PDF, a document with unusual encoding, or a PDF using a CIDFont that PDFBox cannot map can cause the extractor to hang indefinitely or return garbled text. Monitor the extraction path:

#!/bin/bash
# /usr/local/bin/pdfbox-extraction-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/def456"
PDF_SERVICE="http://pdfservice.internal:8080"
TIMEOUT=30
EXPECTED_TEXT="monitoring"  # Expected text in the test PDF

# Submit a known-good PDF for text extraction
# Use a small test PDF stored in the service or passed as base64
EXTRACTION_RESPONSE=$(curl -sf \
  --max-time "$TIMEOUT" \
  -X POST \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{"pdfUrl": "http://pdfservice.internal:8080/test/sample.pdf"}' \
  "${PDF_SERVICE}/api/pdf/extract" 2>/dev/null)

if echo "$EXTRACTION_RESPONSE" | python3 -c "
import sys, json, os
try:
    data = json.load(sys.stdin)
    extracted_text = data.get('text', '')
    expected = os.environ.get('EXPECTED_TEXT', 'monitoring')
    if expected.lower() in extracted_text.lower() and len(extracted_text) > 10:
        sys.exit(0)
    print(f'Text extraction returned: {repr(extracted_text[:100])}', file=sys.stderr)
    sys.exit(1)
except Exception as e:
    print(f'Parse error: {e}', file=sys.stderr)
    sys.exit(1)
" 2>/dev/null; then
  echo "PDF text extraction healthy"
  curl -s "$HEARTBEAT_URL"
else
  echo "PDF text extraction failed or returned unexpected content"
  exit 1
fi

Set the heartbeat to 5 minutes.


Step 4: Monitor JVM Heap Usage

PDFBox holds entire PDF documents in memory during processing — a 100MB PDF can easily consume 500MB of heap during rendering or text extraction. When concurrent processing requests push heap usage toward the JVM's -Xmx limit, GC thrash begins, processing times increase exponentially, and eventually the JVM throws OutOfMemoryError. If the application uses Spring Boot Actuator, the JVM metrics endpoint provides heap usage data:

#!/bin/bash
# /usr/local/bin/pdfbox-jvm-check.sh

HEARTBEAT_URL="https://vigilmon.online/heartbeat/ghi789"
PDF_SERVICE="http://pdfservice.internal:8080"
TIMEOUT=10
MAX_HEAP_PCT=85  # Alert when heap usage exceeds 85%

# Spring Boot Actuator JVM heap metric
HEAP_RESPONSE=$(curl -sf \
  --max-time "$TIMEOUT" \
  "${PDF_SERVICE}/actuator/metrics/jvm.memory.used?tag=area:heap" 2>/dev/null)

HEAP_MAX_RESPONSE=$(curl -sf \
  --max-time "$TIMEOUT" \
  "${PDF_SERVICE}/actuator/metrics/jvm.memory.max?tag=area:heap" 2>/dev/null)

if [ -z "$HEAP_RESPONSE" ] || [ -z "$HEAP_MAX_RESPONSE" ]; then
  echo "JVM heap metrics unavailable — service may be down"
  exit 1
fi

python3 -c "
import sys, json
try:
    used_data = json.loads('''${HEAP_RESPONSE}''')
    max_data = json.loads('''${HEAP_MAX_RESPONSE}''')

    used_bytes = used_data['measurements'][0]['value']
    max_bytes = max_data['measurements'][0]['value']

    if max_bytes <= 0:
        print('Invalid max heap value', file=sys.stderr)
        sys.exit(1)

    heap_pct = (used_bytes / max_bytes) * 100
    print(f'Heap usage: {heap_pct:.1f}% ({used_bytes/1024/1024:.0f}MB / {max_bytes/1024/1024:.0f}MB)')

    if heap_pct > ${MAX_HEAP_PCT}:
        print(f'WARNING: Heap usage {heap_pct:.1f}% exceeds threshold {${MAX_HEAP_PCT}}%', file=sys.stderr)
        sys.exit(1)
    sys.exit(0)
except Exception as e:
    print(f'Parse error: {e}', file=sys.stderr)
    sys.exit(1)
" 2>/dev/null && curl -s "$HEARTBEAT_URL" || exit 1

Install the cron job:

chmod +x /usr/local/bin/pdfbox-jvm-check.sh
(crontab -l 2>/dev/null; echo "*/3 * * * * /usr/local/bin/pdfbox-jvm-check.sh >> /var/log/pdfbox-jvm.log 2>&1") | crontab -

Set the heartbeat to 3 minutes — heap exhaustion can progress from warning to crash within a single processing cycle.


Step 5: Alert Configuration

Configure Vigilmon alerts for PDF service incidents:

  1. Open your PDF service monitors in the Vigilmon dashboard.
  2. Click AlertsAdd alert channel.
  3. Add your notification channels (email, Slack, PagerDuty, webhook).
  4. For the HTTP endpoint monitor: set Alert after to 2 consecutive failures.
  5. For the JVM heap monitor: set Alert after to 1 failure — heap pressure above 85% requires immediate attention to avoid a service crash.
  6. Enable Recovery alerts to confirm when the service recovers after heap pressure subsides or the process is restarted.

Step 6: Validate Your Monitoring Setup

Test each monitor before production load arrives:

# Test the generation check against a live service
chmod +x /usr/local/bin/pdfbox-generation-check.sh
/usr/local/bin/pdfbox-generation-check.sh
# Should print "PDF generation healthy" and exit 0

# Test the JVM heap check
chmod +x /usr/local/bin/pdfbox-jvm-check.sh
/usr/local/bin/pdfbox-jvm-check.sh
# Should print heap usage percentage and exit 0 (unless heap is genuinely near the limit)

# Confirm Vigilmon dashboard shows all monitors green

What to Monitor in Production

| Monitor | Type | Interval | What it catches | |---------|------|----------|-----------------| | HTTP health endpoint | HTTP/HTTPS | 1 min | JVM crash, app server failure | | PDF generation | Cron heartbeat | 5 min | PDFBox rendering failure, zero-byte output | | PDF text extraction | Cron heartbeat | 5 min | Extractor hang, font mapping failure | | JVM heap usage | Cron heartbeat | 3 min | Memory pressure, GC thrash, OOM risk |


Summary

Apache PDFBox-based services fail in ways that standard HTTP monitoring misses: the service responds with HTTP 200 while returning a zero-byte PDF, the extractor hangs indefinitely on a malformed document, or heap exhaustion silently degrades processing throughput before an OOM crash. External monitoring with Vigilmon covers the full failure surface: HTTP monitoring catches process-level failures, synthetic generation checks validate actual PDF output size, extraction checks confirm the full text pipeline works, and JVM heap monitoring catches the memory pressure that precedes crashes. Deploy the generation and heap monitors first for the most critical coverage, then add the extraction monitor once your extraction API endpoint is stable.

Start monitoring Apache PDFBox services for free with Vigilmon →

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →