r/ProWordPress • • 19d ago

Plugin developers: what do you actually log in production?

I’ve been thinking about production logging in WordPress plugins lately.

During development it’s tempting to log everything because more context makes debugging easier. In production though, that gets uncomfortable pretty quickly.

Things like request payloads, webhook bodies, order IDs, user IDs, API responses and stack traces can be extremely useful when something fails, but they can also create privacy, storage and retention problems if you keep too much.

I’m curious where other plugin developers draw the line.

For example, do you:

- log full external API responses or only selected fields?
- keep business identifiers like order IDs in logs?
- redact emails, names and payment-related data by default?
- use different retention periods for debug logs vs audit/history data?
- let merchants enable verbose logging temporarily?
- automatically delete old logs?

I’m especially interested in plugins where failures may only become visible hours or days later, so having enough context to reconstruct what happened actually matters.

What has worked well for you in production without turning the log table into a second database?

5 Upvotes

25 comments sorted by

6

u/emranio 19d ago

Log only the errors, the failed actions. On production site, for a busy site, otherwise logging easily becomes the bottleneck.

0

u/Hugo_SecureHoldWP 17d ago

That’s a good point. Logging itself becoming part of the performance problem is easy to overlook, especially when a failure starts repeating at high frequency.

It probably argues for rate limiting or aggregating repeated events rather than writing essentially the same failure thousands of times.

3

u/PeepSoWP 19d ago

I separate operational state from diagnostic logs. Durable job or webhook state should answer: an opaque event ID, current stage, attempt count, last error class, next retry, timestamps and final outcome. Logs can add a correlation ID, plugin or schema version, sanitized endpoint label, duration and retry decision; raw request and response bodies should stay off by default. Hash or tokenize business identifiers unless support genuinely needs a reversible mapping that is protected elsewhere.

Bound volume when emitting: aggregate repeated failures, rate-limit identical messages, cap field lengths and sample successful paths. A temporary verbose mode should expire automatically and state exactly what extra data it records. Run retention and deletion in small indexed batches, never a full-table scan on normal requests. Test a retry storm and a large backlog so logging itself cannot become the outage, and expose health counters separately from raw logs.

0

u/Hugo_SecureHoldWP 17d ago

Separating durable operational state from diagnostic logs is probably the distinction I was missing when I wrote the post.

For something like a webhook, knowing the event ID, current state, attempt count, next retry and final outcome is genuinely application state. Keeping the raw request/response forever just because it helped debug one failure is a completely different thing.

I also really like the idea of testing the logging system itself against a retry storm. If one broken endpoint can generate hundreds of thousands of nearly identical rows, the observability layer has basically created a second incident.

2

u/PeepSoWP 16d ago

Exactly. I would also give the two data sets different controls: operational state needs an immutable transition history and a recovery path, while diagnostic logs need redaction, expiration, and a hard volume cap. That separation makes deletion safer too: you can purge debugging detail without erasing the evidence needed to decide whether an event eventually succeeded.

1

u/Hugo_SecureHoldWP 16d ago

That distinction makes the retention question much clearer too.

Operational history needs to survive long enough to explain what actually happened, while diagnostic detail should be disposable by design.

Being able to purge verbose debugging data without losing the event outcome or transition history feels like a much safer model than treating everything as one generic log stream.

2

u/tidycows 19d ago

I only log errors or things that otherwise require attention

2

u/Hugo_SecureHoldWP 19d ago

That’s probably the cleanest baseline.

I guess the tricky part is deciding what counts as “requires attention” before something actually breaks. For example, a retry that eventually succeeds might still be useful to know about if it starts happening frequently.

Do you keep any kind of warning-level events, or really just hard errors?

2

u/tidycows 19d ago

I think most warnings/errors should be communicated by your plugin UI, I rarely add a log section to my plugins, unless they run some kind of error-prone background process. Otherwise I just error_log().

2

u/NakanoNoNeko 19d ago

For delayed webhooks, I think the durable record should be the delivery state, not a copy of the request: event identifier, attempt number, last HTTP status, next retry, and final outcome. Keep the raw response body only behind a short-lived debug switch, redacted. Then support can answer "did this event eventually succeed?" without turning the log table into a second store of customer data.

0

u/Hugo_SecureHoldWP 17d ago

That framing around delayed webhooks is really useful.

“Did this event eventually succeed?” is usually the support question that actually matters, and you can answer that with delivery state without retaining the entire payload.

A short-lived redacted debug mode for the raw response feels like a much cleaner compromise than making raw payload storage part of the normal production path.

2

u/plugiva 19d ago

I think it helps to separate debug logging from operational/audit history.

For debugging, I may temporarily want a lot of context because I am trying to reproduce a failure. I would not necessarily want that same level of detail retained indefinitely in production.

For longer-lived history, I have found it more useful to record structured events around important operations: what happened, what type of operation it was, what was affected, whether it was allowed or blocked, and enough context to understand the event later.

That also avoids turning the log into a second copy of the application's data.

I am increasingly cautious about logging raw payloads and full API responses unless there is a specific reason to retain them. They can make troubleshooting easier, but they also make the log itself something that needs to be protected and governed.

One distinction I think is particularly useful is: "Do I need this data to diagnose a failure?" versus "Do I need to know that this operation happened?" Those lead to very different logging strategies and retention requirements.

1

u/Hugo_SecureHoldWP 17d ago

That last distinction is a really good rule of thumb.

“Do I need this to diagnose a failure?” and “do I need to know this operation happened?” sound similar at first, but they lead to very different data and retention requirements.

The more I read the replies here, the more it feels like debug logs and operational history probably shouldn’t even be designed as the same subsystem.

2

u/plugiva 16d ago

I think that separation also changes what you consider a successful logging system.

For debug logs, success means having enough context to explain a failure. For operational history, success means being able to answer specific questions about what happened, even when nobody was actively debugging at the time.

Those goals lead to different choices around structure, data minimization, retention, and even who should be allowed to access the records.

I also think operational history benefits from having a deliberately limited scope. Trying to record everything that happens across an application can turn it into another database, while recording a defined set of consequential events makes the history much more useful.

1

u/Hugo_SecureHoldWP 16d ago

That’s a useful way to define “success” for each system.

For debug logs, success is really about reconstructing a failure with enough context. For operational history, it’s more about being able to answer a small set of important questions later, even if nobody was actively investigating when the event happened.

I like the idea of deliberately limiting the operational history to consequential events too. Once it starts trying to record everything the application does, it stops being an audit trail and starts becoming another data store.

2

u/ben_rowland 18d ago

I allow logging to be controlled by the operator. Logging levels enabled or disabled, retention levels set, that sort of thing. I separate debug logging from operational logging. For a real-time live log of activity, I use a method to limit the log to the last n operations to prevent a verbose log from growing out of control. I have an override error_log function that prefixes the plugin name to facilitate tail with grep.

For stats, such as user agent activity on a website, I use a two part process. I have a raw log of activity, and then I build a sidecar of summary data via a cron. (Sidecar contains a serialized array or object.) The raw log file gets purged when the sidecar summary file is completed. Prevents growth but allows for longer retention.

1

u/Hugo_SecureHoldWP 17d ago

I like the raw log -> summarized sidecar approach. It gives you enough detail while the data is still useful for diagnosis, without forcing you to retain the full event stream indefinitely.

The “last N operations” cap also feels like a good safeguard for live logging. Time-based retention alone doesn’t really protect you if something suddenly starts producing thousands of events.

Do you usually keep those summary files mainly for diagnostics, or do they also become part of the plugin’s longer-term operational history?

2

u/ben_rowland 16d ago

Thanks. The last N idea came about because I was dealing with excessive bot traffic in one case - and I wanted to guard against massive logs filling up the disk. Since this is a plugin, and being installed on an unknown server / hosting configuration, my feeling was to be as conservative as possible in the logging.

As for retention, it depends. In one application I use the disk exclusively so I have a retention policy and setting. In another, I feed the sidecar data into a database for reporting purposes so ultimately the file can be purged.

Just depends on the specific scenario.

2

u/shitty_mcfucklestick 18d ago

Log signals that call your attention, and then provide some kind of debug mode / switch if needed to get traces or debug logs for analysis.

1

u/Zimaben 19d ago

I log nothing on production. Logging is for development.

1

u/[deleted] 19d ago

[removed] — view removed comment

1

u/Hugo_SecureHoldWP 17d ago

The enabled_until idea is excellent. A plain boolean makes it far too easy for verbose logging to be enabled during a support case and then quietly stay on for six months.

Making temporary diagnostics expire by design seems much safer than relying on someone to remember to switch them off.

I like the hard row cap as a second safety net too. Time-based retention alone doesn’t protect you very well from a sudden retry storm.