Module: Heatwave::XmlLogSummary
- Defined in:
- app/lib/heatwave/xml_log_summary.rb
Overview
Summarises XML payloads before persisting them to shipping_api_log.
Some carrier responses inline very large blobs (Base64-encoded PDF labels,
signature images, multi-page BOL bytes) into the same XML envelope as the
interesting status fields. R+L Carriers' CreateBillOfLadingResponse, for
example, includes a <PdfDocument> element with the full BOL PDF — tens
to hundreds of kilobytes of Base64 — alongside a ~50-byte success flag.
Keeping those bytes in the log column makes the Shipping API Log tab
unreadable and blows up the JSONB row. The PDFs themselves are already
extracted into the shipment's Attachments, so the log column only needs
enough to triage failures.
This module walks the XML tree, truncates any text node longer than
DEFAULT_MAX_LEN characters to its prefix plus a "[truncated, N chars
total]" marker, and re-emits the document pretty-printed with two-space
indent for readability. Non-XML strings, parse errors, and blank inputs
are returned untouched so callers can pass through whatever the carrier
actually returned without a defensive is_xml? check.
Constant Summary collapse
- DEFAULT_MAX_LEN =
The 100-char threshold per the original product ask. Big enough to keep
tracking numbers, BOL IDs, error messages, and small status fields
intact; tight enough to clip Base64 image bytes after the first line. 100
Class Method Summary collapse
-
.call(xml_string, max_len: DEFAULT_MAX_LEN) ⇒ String
Sanitized + pretty-printed XML, or the original string unchanged if it was blank or didn't parse as XML.
Class Method Details
.call(xml_string, max_len: DEFAULT_MAX_LEN) ⇒ String
Returns sanitized + pretty-printed XML, or the original string
unchanged if it was blank or didn't parse as XML.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'app/lib/heatwave/xml_log_summary.rb', line 40 def self.call(xml_string, max_len: DEFAULT_MAX_LEN) return xml_string unless xml_string.is_a?(String) && xml_string.strip.length.positive? doc = REXML::Document.new(xml_string) return xml_string unless doc.root # tolerated REXML "parsed nothing" case walk_and_truncate(doc.root, max_len) out = +'' formatter = REXML::Formatters::Pretty.new(2) # `compact = true` keeps elements that only have small text content on # a single line (`<WasSuccess>true</WasSuccess>`) instead of splitting # across three lines each — easier to scan in the log tab. formatter.compact = true formatter.write(doc, out) out rescue REXML::ParseException xml_string end |