Logging adalah salah satu aspek paling penting dalam运维 aplikasi production. Ketika sesuatu salah (dan pasti akan salah), log adalah satu-satunya petunjuk yang kamu punya untuk menemukan dan memperbaiki masalah.
Tapi logging yang buruk justru membuat debugging lebih sulit. Terlalu banyak log = noise. Terlalu sedikit log = tidak ada petunjuk. Log yang tidak structured = tidak bisa dianalisis.
Berikut best practices untuk logging di production.
Kenapa Logging Penting?
- Debugging — temukan error dan root cause
- Monitoring — pantau health aplikasi
- Audit trail — catatan aktivitas user
- Security — deteksi aktivitas mencurigakan
- Performance — identifikasi bottleneck
Structured vs Unstructured Logging
❌ Unstructured Logging
console.log('User login: ' + userId);
console.log('Database query took ' + duration + 'ms');
console.log('Error occurred: ' + error.message);
Masalah:
- Sulit di-parse oleh log management tools
- Tidak bisa di-filter berdasarkan field
- Format tidak konsisten
- Tidak bisa dianalisis secara programmatic
✅ Structured Logging
console.log(JSON.stringify({
level: 'info',
message: 'User login',
userId: '12345',
timestamp: new Date().toISOString()
}));
console.log(JSON.stringify({
level: 'info',
message: 'Database query completed',
duration: 45,
query: 'SELECT * FROM users',
timestamp: new Date().toISOString()
}));
console.log(JSON.stringify({
level: 'error',
message: 'Database connection failed',
error: 'Connection refused',
host: 'localhost',
port: 5432,
timestamp: new Date().toISOString()
}));
Kelebihan:
- Mudah di-parse oleh tools seperti ELK, Datadog, Grafana
- Bisa difilter berdasarkan field (level, userId, dll)
- Format konsisten
- Bisa dianalisis secara programmatic
Log Levels
Gunakan log levels dengan benar:
| Level | Kapan Digunakan | Contoh |
|---|---|---|
| DEBUG | Informasi untuk debugging, hanya di development | Variable values, function calls |
| INFO | Events normal yang perlu dicatat | User login, deployment selesai |
| WARN | Situasi yang tidak error tapi perlu perhatian | Retry attempt, deprecation warning |
| ERROR | Error yang terjadi, perlu investigasi | Database connection failed, API error |
| FATAL | Error kritis, aplikasi tidak bisa jalan | Out of memory, disk full |
// ❌ Salah — semua di-console.log
console.log('User logged in');
console.log('Database error');
console.log('API failed');
// ✅ Benar — pakai levels yang tepat
logger.info('User logged in', { userId: '12345' });
logger.error('Database connection failed', { error: err.message });
logger.fatal('Out of memory', { heapUsed: process.memoryUsage().heapUsed });
Apa yang Perlu Di-Log
✅ Log Ini
- User actions — login, logout, create, update, delete
- API requests — method, path, status code, duration
- Errors — full error message, stack trace, context
- System events — startup, shutdown, config changes
- Performance metrics — response time, memory usage
- Security events — failed login, permission denied
❌ Jangan Log Ini
- Secrets — passwords, API keys, tokens
- Sensitive user data — credit card, SSN, full address
- Request/response bodies — bisa sangat besar
- Health checks — terlalu verbose, noise
- Debug info di production — hanya untuk development
Contoh Logging yang Baik
Node.js / Express
const morgan = require('morgan');
const winston = require('winston');
// HTTP request logging
app.use(morgan('combined'));
// Application logging
const logger = winston.createLogger({
level: process.env.LOG_LEVEL || 'info',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.json()
),
transports: [
new winston.transports.Console(),
],
});
// Contoh penggunaan
app.get('/api/users', async (req, res) => {
const startTime = Date.now();
try {
const users = await User.findAll();
logger.info('Users fetched', {
count: users.length,
duration: Date.now() - startTime,
});
res.json(users);
} catch (error) {
logger.error('Failed to fetch users', {
error: error.message,
stack: error.stack,
duration: Date.now() - startTime,
});
res.status(500).json({ error: 'Internal server error' });
}
});
Python / FastAPI
import logging
import time
from fastapi import FastAPI, Request
# Setup logging
logging.basicConfig(
level=logging.INFO,
format='{"time":"%(asctime)s","level":"%(levelname)s","message":"%(message)s",%(extras)s}'
)
logger = logging.getLogger(__name__)
@app.middleware("http")
async def log_requests(request: Request, call_next):
start_time = time.time()
response = await call_next(request)
duration = (time.time() - start_time) * 1000
logger.info('Request completed', extra={
'method': request.method,
'path': request.url.path,
'status': response.status_code,
'duration': round(duration, 2),
})
return response
@app.get("/api/users")
async def get_users():
start_time = time.time()
try:
users = await fetch_users()
logger.info('Users fetched', extra={
'count': len(users),
'duration': round((time.time() - start_time) * 1000, 2),
})
return users
except Exception as e:
logger.error('Failed to fetch users', extra={
'error': str(e),
'duration': round((time.time() - start_time) * 1000, 2),
})
raise
Laravel / PHP
<?php
// routes/web.php
use Illuminate\Support\Facades\Log;
Route::get('/api/users', function () {
$startTime = microtime(true);
try {
$users = User::all();
Log::info('Users fetched', [
'count' => $users->count(),
'duration' => round((microtime(true) - $startTime) * 1000, 2),
]);
return response()->json($users);
} catch (\Exception $e) {
Log::error('Failed to fetch users', [
'error' => $e->getMessage(),
'duration' => round((microtime(true) - $startTime) * 1000, 2),
]);
return response()->json(['error' => 'Internal server error'], 500);
}
});
Log Aggregation
Di production, log dari beberapa instance perlu di-aggregate. Tools yang umum digunakan:
| Tool | Description | Free Tier |
|---|---|---|
| Helipod Dashboard | Logs real-time dari dashboard | ✅ Included |
| ELK Stack | Elasticsearch + Logstash + Kibana | Self-hosted |
| Grafana Loki | Log aggregation, integrated with Grafana | Self-hosted |
| Datadog | Full observability platform | Trial |
| Betterstack | Cloud logging | Free tier |
Di Helipod, logs tersedia real-time dari dashboard — tidak perlu setup ELK atau tools tambahan.
Performance Logging
Log performance metrics untuk identifikasi bottleneck:
// Response time logging
app.use((req, res, next) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
if (duration > 1000) { // Log slow requests
logger.warn('Slow request', {
method: req.method,
path: req.path,
duration,
statusCode: res.statusCode,
});
}
});
next();
});
// Database query logging
const originalQuery = db.query;
db.query = function (...args) {
const start = Date.now();
const result = originalQuery.apply(this, args);
const duration = Date.now() - start;
if (duration > 100) { // Log slow queries
logger.warn('Slow database query', {
query: args[0],
duration,
});
}
return result;
};
Security Logging
Log events keamanan untuk audit dan deteksi anomali:
// Failed login attempts
logger.warn('Failed login attempt', {
email: req.body.email,
ip: req.ip,
userAgent: req.headers['user-agent'],
});
// Permission denied
logger.warn('Permission denied', {
userId: req.user.id,
resource: req.path,
method: req.method,
});
// Rate limiting triggered
logger.warn('Rate limit triggered', {
ip: req.ip,
path: req.path,
count: req.rateLimit.current,
});
Log Retention
Atur berapa lama log disimpan:
| Environment | Retention | Reason |
|---|---|---|
| Development | 7 days | Cukup untuk debugging |
| Staging | 30 days | Untuk testing dan validation |
| Production | 90 days | Compliance dan audit |
Checklist Logging
- Gunakan structured logging (JSON format)
- Gunakan log levels dengan benar
- Log user actions dan system events
- Log errors dengan full context
- Jangan log secrets atau sensitive data
- Log performance metrics (response time, duration)
- Log security events (failed login, permission denied)
- Setup log aggregation
- Atur log retention policy
- Monitor error rate
Hubungannya dengan Helipod
Helipod menyediakan logging bawaan untuk semua pod:
- Logs real-time — akses langsung dari dashboard
- Filter by pod — pisahkan log per service
- Search — cari log berdasarkan keyword
- Export — download logs untuk analisis
Kamu tidak perlu setup ELK, Grafana Loki, atau tools logging lainnya. Logging sudah termasuk.
Kesimpulan
Logging yang baik adalah kunci untuk debugging dan monitoring di production. Dengan structured logging, log levels yang benar, dan tools yang tepat, kamu bisa mengurangi waktu debugging dan meningkatkan reliability aplikasi.
Mulai deploy di helipod.io — logs real-time sudah termasuk, tidak perlu setup tambahan.
Punya pertanyaan? Hubungi kami di support@helipod.id atau bergabung ke komunitas di hangar.helipod.io.