Logs are what your application remembers about itself. During normal development they help a person understand what happened. During an incident they become evidence: which request failed, which service handled it, which customer was affected, which deployment introduced the change, and whether the same failure is spreading.
Plain text logs and structured logs both answer those questions, but not with the same reliability. Plain text logs are easy to write and easy to read in a terminal. Structured logs turn each event into fields that machines can index, filter, join, alert on, and correlate with traces and metrics.
The decision is not really about whether JSON looks nicer than a sentence. It is about who needs to use the log later. If a developer is reading one file on a laptop, a clear sentence may be enough. If an operations team is searching millions of events across services, structured fields are usually the difference between fast investigation and improvised text archaeology.
What Plain Text Logs Are
Plain text logging writes events as human-oriented strings. A line might include a timestamp, level, service name, and message:
2026-05-05T14:30:45Z ERROR orders Database connection failed requestId=req_12345 retry=true
This is compact and readable. A developer can skim it quickly, paste it into a chat, or search with ordinary command-line tools. For small scripts, one-off jobs, local development, and simple services, plain text can be perfectly reasonable.
The weakness appears when another system needs to understand the line. If a log platform wants to find all errors for requestId=req_12345, it has to parse the message. If the service later writes request_id=req_12345 or request req_12345 failed, the parser may miss it. Plain text relies on convention, and conventions drift.
What Structured Logs Are
Structured logging writes each event as data. JSON is common because it is widely supported, but the important part is the field model, not the file extension.
{
"timestamp": "2026-05-05T14:30:45Z",
"level": "error",
"service": "orders",
"environment": "production",
"message": "Database connection failed",
"request_id": "req_12345",
"trace_id": "tr_8f2d",
"retryable": true,
"error_code": "DB_CONNECT_FAILED"
}
Now the log platform does not need to guess where the request ID lives. It is a field. Alerts can filter on level:error and error_code:DB_CONNECT_FAILED. Dashboards can count failures by service, deployment, region, or customer tier. Engineers can move from a trace to the exact logs for that request.
Structured logs can still be readable. A good structured entry includes a short message field for humans and stable keys for machines. The best practice is not “remove prose.” It is “do not make prose carry all the meaning.”
The Incident Response Difference
Imagine a checkout incident. Customers are reporting failed payments, but only for some orders. With plain text logs, the team may start searching for words like payment, failed, declined, and timeout. That can work, but it depends on every service using consistent phrasing.
With structured logs, the investigation can start with fields:
service = payments
level = error
error_code = PAYMENT_PROVIDER_TIMEOUT
deployment_id = 2026.05.05.3
Then the team can group by region, provider, payment_method, or trace_id. The question changes from “what did someone happen to write in the message?” to “what dimensions did we record when the event occurred?”
This is where structured logging pays for itself. It reduces the distance between a symptom and a useful slice of evidence. It also makes alerts less brittle, because they can trigger on stable fields instead of fragile text matching.
Where Plain Text Still Makes Sense
Plain text is not obsolete. It is often the right choice for short-lived scripts, developer-only tools, local debugging, and environments without structured ingestion. If a migration script runs once and a person is watching the output, clear plain text may be more useful than verbose JSON.
Plain text can also be a good interface for command-line tools. A tool that prints:
Imported 482 records from customers.csv
Skipped 7 invalid rows
is doing the right thing for a human operator. If that same import becomes a scheduled production job with alerts, retries, audit requirements, and dashboards, structured logs become more attractive.
The practical distinction is scale and automation. The more logs need to be searched by machines, correlated across systems, or used for alerting, the more valuable structure becomes.
Fields That Matter
Structured logging works only when the fields are chosen deliberately. A service that logs arbitrary JSON blobs with random keys is not much better than plain text. Start with a small shared schema and expand carefully.
Useful baseline fields include:
timestamplevelmessageserviceenvironmentversionordeployment_idrequest_idorcorrelation_idtrace_idwhen tracing is availableerror_codefor known failuresduration_msfor timed operations
Domain fields should be added when they help investigation. An orders service may include order_id; a billing service may include invoice_id; a background worker may include job_id. Avoid dumping entire request bodies into logs. Good fields answer likely operational questions without leaking sensitive data or exploding storage.
Cost and Noise
Structured logs are often larger than plain text logs. They may increase ingestion volume, indexing cost, and storage cost. That does not make them bad; it means the logging strategy needs limits.
Common controls include sampling high-volume success events, logging debug fields only in lower environments, redacting sensitive values, dropping noisy fields before ingestion, and separating audit logs from application diagnostics. It is also worth deciding which fields should be indexed. Indexing everything can be expensive and unnecessary.
The worst outcome is a structured logging migration that turns every object into a log event. More data is not automatically more observability. The goal is useful context, consistently named and available when something breaks.
Migration Strategy
Most teams do not need to switch everything in one release. A safer migration keeps the human-readable message and adds structured fields around it. That way existing workflows continue to work while log search and alerting improve.
Start with the busiest incident paths. Add request IDs, trace IDs, service names, error codes, and deployment metadata. Standardize field names across services. Update dashboards and alerts to use fields rather than text parsing. Then expand to domain-specific fields where they help answer real support and operations questions.
For example, a plain text log:
Payment failed for order ord_123
can become:
{
"level": "warn",
"service": "checkout",
"message": "Payment failed",
"order_id": "ord_123",
"provider": "stripe",
"error_code": "PAYMENT_DECLINED"
}
The message is still readable, but the event is now queryable.
Security and Privacy
Structured logging makes it easier to search sensitive fields, which means it also makes leaks easier to exploit if logging is careless. Never treat logs as a safe place for secrets. Avoid access tokens, API keys, passwords, raw authorization headers, full payment details, and unnecessary personal data.
Redaction should happen before logs leave the application when possible, and again in the log pipeline as a backstop. Field-level controls are easier with structured logs because the system can redact email, token, or authorization fields by name. Plain text redaction often depends on less reliable pattern matching.
Logs are operational records. They deserve retention limits, access controls, and review just like other production data.
Recommendation
Use plain text for small, local, human-first workflows. Use structured logging for production services, distributed systems, background jobs, APIs, and anything that needs reliable search, alerting, or incident investigation.
The most effective compromise is simple: always include a readable message, but do not hide important context inside it. Put stable operational facts into fields. That gives humans something easy to scan and gives systems something dependable to query.
References
These references are useful for structured logging conventions and implementation details:
- OpenTelemetry logs data model
- Elastic Common Schema
- Google Cloud structured logging
- Microsoft ILogger documentation
- Pino documentation
Conclusion
Plain text logs are easy for people to read. Structured logs are easier for systems to search, correlate, alert on, and analyze at scale. Neither style is universally right, but production systems usually benefit from structured fields because incidents demand fast, precise questions.
The best logging is both humane and machine-readable: a clear message, consistent fields, useful context, and enough restraint to avoid turning observability into noise.





