Lorixen.
EN

Log the Shape of an Enquiry, Not Its Words

When a contact form or enquiry API misbehaves, the fastest debugging aid is a log of the payload. It is also the easiest way to copy names, phone numbers and free text into a system that more people can read than the enquiry inbox. This article proposes a design where the log records the shape of an enquiry and not its content. Everything here is a recommendation to adapt, not a description of anything already built.

The primary artifact: an allowlist

The rule is that a field reaches the log only if it is named on a list. Unknown fields are dropped, never passed through. A denylist fails silently when someone adds a new field next month. An allowlist fails safe, because the new field is simply absent until someone decides it belongs.

Each allowlisted field has one of three treatments:

  • Pass: copied as is. Only for values that carry no personal content, such as an identifier you generated, a timestamp, a form type, or validation error codes.
  • Derive: replaced by a fact about the value, such as a present or absent flag, a length, or a count.
  • Drop: not logged at all. This is the default.

Worked example (hypothetical)

An enquiry arrives with 10 fields: enquiry_id, received_at, form_type, name, email, phone, message, attachment_names, referrer_url, validation_errors.

The allowlist applies as follows.

  • Pass (4): enquiry_id, received_at, form_type, validation_errors (codes only, such as EMAIL_FORMAT).
  • Derive (3 sources, 5 outputs): name becomes name_present, email becomes email_present, phone becomes phone_present, message becomes message_length, attachment_names becomes attachment_count.
  • Drop (1): referrer_url, because query strings in a URL may carry tokens or personal values.

Check the counts: 4 passed plus 5 derived gives 9 output keys. The 10 inputs split into 4 passed, 5 derived sources and 1 dropped, which is 10. Wait, the derived sources are name, email, phone, message and attachment_names, so that is 5 sources, not 3. The correct split is 4 passed, 5 derived sources and 1 dropped, totalling 10.

The redacted diagnostic fixture for this enquiry is then:

enquiry_id: E-1001, received_at: 2026-11-02T09:15:00Z, form_type: quote_request, validation_errors: [EMAIL_FORMAT], name_present: true, email_present: true, phone_present: false, message_length: 214, attachment_count: 1, dropped_unknown_fields: 0

That is 10 keys, 9 above plus the dropped_unknown_fields counter, which tells you the allowlist is working without revealing what was dropped. If a form later gains a field called company, the counter reads 1 and nobody has to guess.

The fixture is useful: it shows an invalid email, a missing phone and a message of known length, which is usually enough to reproduce a validation bug.

Layered constraints

Treat the allowlist as one layer among several, not a guarantee. Other layers worth considering: apply redaction at the point where the log record is built, not in a later cleanup job; keep error messages from libraries out of logs when they might echo input; restrict who can read diagnostic logs; and keep a separate, access-controlled path for the rare case where raw content is truly needed.

Stop conditions

Stop and reassess the design if any of these appear:

  • Someone proposes passing the message body 'just for now'. Derive its length instead.
  • A derived field starts to reveal content, for example a hash of an email that could be matched against a known list. Prefer a boolean.
  • The dropped_unknown_fields counter is nonzero in production for a form you thought you knew. Review the form before changing the allowlist.

Acceptance tests (proposed, not performed)

  1. Feed the 10 field sample above and compare the output with the fixture key for key.
  2. Add an eleventh unknown field containing a recognisable marker string. Expect it absent from output and the counter equal to 1.
  3. Search all log output produced by the test run for the marker strings placed in name, email, phone and message. Expect no matches.
  4. Send a payload with a malformed shape, such as message as a list. Expect a record with an error code and no echoed content.
  5. Remove the allowlist file. Expect the logger to emit only identifier and timestamp, not everything.

The last test matters most: a missing configuration should degrade toward logging less.

Sources

    WhatsAppLet’s talk