NEWAuto-scale sesuai traffic
Bonus 25%!0h
Detail
loggingmonitoringproductiondevopsbest practice

Logging Best Practices untuk Aplikasi Production

Tim Helipod

7 menit baca

Logging yang baik = debugging yang mudah. Pelajari cara menulis log yang useful untuk production — dari structured logging sampai log levels.

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.

Siap coba Helipod?

Deploy aplikasi kamu sekarang. Gratis, tanpa kartu kredit.

Mulai Gratis →