Why Most Developers Fail at Logging and How to Master It
This article reveals common logging pitfalls that cause silent failures, explains three levels of logging maturity from rookie to expert, and provides concrete Java code examples, structured‑logging techniques, MDC usage, and automated alerting to turn logs into a powerful observability tool.
Introduction
During a holiday, the author noticed a disk‑space alert caused by oversized log files, prompting a reflection on how logging—an everyday task for developers—can easily become a hidden source of serious problems if mishandled.
Act 1: Rookie Logging Pitfalls
New engineers often log without purpose, leading to three typical issues:
Exception swallowed : The catch block discards the exception without stack trace, making debugging impossible.
No key information : Log messages like log.info("111") or log.info("Reached here") provide no context such as order ID or user.
Vague error messages : Messages like "OrderService #order process error!" lack details about which order or user triggered the error.
Example of a problematic snippet:
@Service
public class OrderService {
public void processOrder(OrderDTO order) {
try {
// ...50 lines of business logic...
// Potential NPE when order.getCustomer() returns null
String customerName = order.getCustomer().getName();
log.info("OrderService start process order..."); // no useful info
// ...more logic...
} catch (Exception e) {
// Exception swallowed
log.error("OrderService #order process error!");
}
}
}Act 2: The Three Levels of Logging Maturity
Level 1 – P4 Rookie: "Graffiti" Logging
Uses System.out.println() or e.printStackTrace().
Logs arbitrary strings without structure.
Often concatenates strings (e.g., "value=" + var), causing performance loss.
Consequences: performance killers, lost information, and logs that cannot be aggregated.
Level 2 – P5 Intermediate: "Business Ledger" Logging
Code still misses key details and proper exception propagation:
@Service
public class OrderService {
public void createOrder(OrderDTO order) {
try {
// ...business logic...
String userName = null;
userName.toLowerCase(); // NPE
} catch (Exception e) {
// No log, just rethrow vague BizException
throw new BizException("Create order failed");
}
}
}
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
@PostMapping("/orders")
public void createOrder(@RequestBody OrderDTO order) {
try {
orderService.createOrder(order);
} catch (BizException e) {
log.error("Failed to handle create order request!", e);
}
}
}Issues: logs only state "order creation failed" without the root cause, and missing trace IDs make correlation across services impossible.
Level 3 – P6/P7 Expert: "Sky‑Net" Logging
Experts focus on observability and diagnosability:
Structured logging : output JSON with fields like event, order_id, user_id, error.
Context is king : Use MDC to attach trace_id to every log entry.
Log as a bomb : Avoid logging huge objects; sample high‑frequency logs.
Example of structured log:
log.error("{\"event\":\"order_creation_failed\",\"order_id\":\"{}\",\"user_id\":\"{}\",\"error\":\"{}\"}", orderId, userId, e.getMessage());MDC interceptor example:
public class TraceInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
String traceId = UUID.randomUUID().toString();
MDC.put("trace_id", traceId);
return true;
}
}With MDC, a later log automatically includes the trace ID:
log.error("Order failed, orderId: {}", orderId); // trace_id added implicitlyAct 3: The Ultimate Mature Logging System
A mature system provides three core capabilities:
Global visibility : Correlate requests across micro‑services using trace_id to build a complete call chain.
Right‑sized data presentation : Store logs in concise JSON (timestamp, trace_id, span_id, error_code) and apply retention policies (e.g., 7‑day or 1 GB size limits) to avoid disk‑space bombs.
Proactive automated response : Detect error‑rate spikes, trigger alerts (e.g., via DingTalk), and optionally launch auto‑remediation scripts such as isolating faulty nodes or rolling back configurations.
The evolution from passive record‑keeping to an active guardian reflects an engineer’s growth in system mastery.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
dbaplus Community
Enterprise-level professional community for Database, BigData, and AIOps. Daily original articles, weekly online tech talks, monthly offline salons, and quarterly XCOPS&DAMS conferences—delivered by industry experts.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
