Log levels tell you how important or severe a log message is.
Think of them as a way to classify what your backend is reporting.
A common hierarchy is:
TRACE
↓
DEBUG
↓
INFO
↓
WARN
↓
ERROR
↓
FATALNot every logging library supports all of these.
1. TRACE
Very detailed information for tracing exactly what the program is doing.
Example:
TRACE Entering TaskService.createTask()
TRACE taskId = 42
TRACE Checking project membership
TRACE Query completed in 12msUsually only useful when debugging complicated problems.
2. DEBUG
Information useful to developers while debugging.
Example:
DEBUG User 42 requested project 10
DEBUG Querying tasks for project 10
DEBUG Found 15 tasksYou generally don’t want huge amounts of DEBUG logs in production.
3. INFO
Normal, meaningful events that show that the system is working.
Examples:
INFO Server started on port 3000
INFO User 42 logged in
INFO Task 15 created
INFO Database connection establishedThink:
“Something happened, and it’s useful to know.”
This is often your default production log level.
4. WARN
Something unusual or potentially problematic happened, but the application can continue working.
Examples:
WARN Login failed for user 42
WARN API request took 2.5 seconds
WARN Database connection pool is 80% full
WARN Refresh token is close to expirationThink:
“Something isn’t quite right.”
A warning isn’t necessarily an error.
5. ERROR
Something failed and an operation couldn’t be completed correctly.
Examples:
ERROR Failed to create task
ERROR Database query failed
ERROR Payment processing failed
ERROR Unable to send notificationThe application might still be running.
For example:
Request A → ERROR
Request B → works
Request C → worksOne operation failed, but the entire server isn’t necessarily dead.
6. FATAL
A critical error that prevents the application from continuing.
Example:
FATAL Database connection cannot be established
FATAL Application configuration is invalidFor example:
Application starts
↓
Cannot connect to database
↓
Cannot function
↓
FATAL
↓
Process exitsSome logging libraries don’t use FATAL and simply use ERROR.
How filtering works
This is one of the most useful things to understand.
Suppose your configured log level is:
INFOYou generally see:
INFO
WARN
ERROR
FATALbut not:
DEBUG
TRACEBecause DEBUG and TRACE are considered less severe/detailed than INFO.
For example:
Configured level: INFO
TRACE ❌
DEBUG ❌
INFO ✅
WARN ✅
ERROR ✅
FATAL ✅If you configure:
DEBUGyou get:
DEBUG ✅
INFO ✅
WARN ✅
ERROR ✅
FATAL ✅In a backend
Imagine your API receives:
POST /api/tasksYour logs might look like:
INFO POST /api/tasks
DEBUG Request body validated
DEBUG User 42 has ADMIN role
INFO Task created: id=15If something goes wrong:
INFO POST /api/tasks
DEBUG User 42 has ADMIN role
ERROR Failed to insert task into databaseLog level vs log message
These are different things.
INFO: User logged inHere:
INFOis the log level.
And:
User logged inis the log message.
A structured logger might produce:
{
"level": "info",
"message": "User logged in",
"userId": 42
}This is called structured logging, and it’s very useful in production.
The levels I’d focus on
For your backend projects, you don’t need to worry about every possible level initially.
Learn these four very well:
DEBUG → Developer details
INFO → Normal important events
WARN → Something unusual/problematic
ERROR → Something failedA simple rule:
DEBUG = “What is the code doing?”
INFO = “What happened normally?”
WARN = “Something might be wrong.”
ERROR = “Something went wrong.”