Testing, Debugging, Logging, and Observability
Build reliable Node.js applications with unit tests, integration tests, debugging, structured logging, metrics, traces, and health checks.
Unit and Integration Testing
Unit tests verify small pieces of logic in isolation. Integration tests verify interactions between components such as APIs, databases, queues, and external services.
A good test suite balances speed, coverage, and confidence. Not every line requires a unit test; important business behavior and integration boundaries deserve particular attention.
import assert from 'node:assert/strict';
import test from 'node:test';
function add(a, b) {
return a + b;
}
test('adds two numbers', () => {
assert.equal(add(2, 3), 5);
});- Unit tests focus on isolated behavior.
- Integration tests validate collaboration between real components.
- Tests should verify behavior rather than implementation details.
What is an integration test primarily concerned with?
Production Logging
Production applications should use structured logs containing fields such as timestamp, severity, service, request ID, user or correlation identifiers where appropriate, and useful error metadata.
Avoid logging passwords, access tokens, session cookies, API keys, and other sensitive information. JSON logs are convenient for centralized log systems.
Never log authorization headers, passwords, cookies, private keys, refresh tokens, or other sensitive credentials.
function log(level, message, metadata = {}) {
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
level,
message,
...metadata
}));
}
log('info', 'Request completed', {
requestId: 'req-123',
statusCode: 200
});- Use structured logs for production systems.
- Include correlation identifiers when tracing requests across services.
- Redact sensitive values before logging.
Which value should normally never be logged in plaintext?
Metrics, Tracing, and Health Checks
Observability combines logs, metrics, and traces to explain system behavior. Metrics answer questions such as how many requests are arriving, how long they take, and how many fail. Distributed tracing follows a request across services.
Health endpoints should distinguish between basic process liveness and readiness to receive traffic.
- Logs, metrics, and traces provide complementary observability.
- Readiness and liveness checks answer different operational questions.
- Correlation IDs make distributed debugging significantly easier.
What does distributed tracing help you understand?