Ketika ada masalah di production, hal pertama yang kamu buka adalah logs. Logs adalah rekaman jejak setiap yang terjadi di aplikasimu — request yang masuk, error yang terjadi, query yang dijalankan, sampai output dari kode kamu sendiri.
Helipod menyediakan log viewer real-time langsung dari dashboard browser — tidak perlu SSH ke server, tidak perlu install tool tambahan, tidak perlu setup log aggregation sendiri.
Dua Jenis Logs di Helipod
1. Build Logs
Tersedia di tab Deployments → klik deployment → Build logs.
Build logs menampilkan output dari proses build Docker image:
- Clone repository
- Install dependencies (
npm ci,pip install,composer install) - Build step (
next build,nest build,collectstatic) - Push image ke registry
Kapan dibuka: Saat deployment gagal dan kamu perlu tahu di step mana error-nya terjadi.
2. App Logs
Tersedia di tab Deployments → klik deployment → App logs, atau di halaman Logs global (sidebar kiri).
App logs menampilkan stdout dan stderr dari container yang sedang berjalan — semua yang di-print oleh aplikasimu, termasuk:
- Access log (request HTTP yang masuk)
- Error dan exception
console.log()di Node.jsprint()di PythonLog::info()di Laravel- Output dari cron job atau background worker
Kapan dibuka: Debugging masalah runtime, error yang terjadi saat aplikasi berjalan normal.
Halaman Logs Global
Klik ikon Logs di sidebar kiri dashboard (ikon list/terminal) untuk membuka halaman Logs yang menampilkan log dari semua pod dalam project sekaligus.
Anatomi Halaman Logs
Timeline bar di bagian atas menampilkan distribusi log entries per waktu — berguna untuk melihat kapan ada spike error (blok merah) vs log normal (blok hijau/biru).
Filter pod — dropdown "All pods (N)" untuk melihat semua log, atau pilih pod spesifik. Sangat berguna di project multi-service untuk isolasi log per service.
Search bar — ketik keyword untuk filter log secara real-time. Shortcut keyboard: tekan / untuk langsung focus ke search bar.
Time range selector — pilih rentang waktu log yang ingin ditampilkan (default: 1 hour).
Download — export log sebagai file untuk analisis offline.
Kolom Tabel Logs
| Kolom | Keterangan |
|---|---|
| Time (WIB) | Timestamp dalam Waktu Indonesia Barat |
| Pod | Nama service yang generate log |
| Deploy | Commit hash deployment yang sedang berjalan |
| Replica | ID replica spesifik (jika ada multiple replicas) |
| Data | Isi log entry |
Warna Log
- Putih/abu-abu — log normal (INFO, access log, output biasa)
- Merah — error log — langsung mencolok tanpa perlu scroll
Cara Baca Access Log
Access log adalah log HTTP request yang masuk ke aplikasimu. Format standar nginx:
10.42.4.44 - [27/Apr/2026:08:11:44 +0000] "GET / HTTP/1.1" 200 60638 "-" "Uptime-Kuma/1.23.17" "10.42.5.0"
Breakdown setiap field:
| Field | Nilai | Artinya |
|---|---|---|
| IP Client | 10.42.4.44 |
IP pengirim request (internal jika via load balancer) |
| Timestamp | 27/Apr/2026:08:11:44 |
Waktu request diterima |
| Method & Path | GET / HTTP/1.1 |
HTTP method, path, protokol |
| Status Code | 200 |
HTTP response code |
| Response Size | 60638 |
Ukuran response dalam bytes |
| Referer | - |
Halaman asal request |
| User-Agent | Uptime-Kuma/1.23.17 |
Browser/tool yang membuat request |
HTTP Status Code yang Perlu Diperhatikan
| Code | Arti | Tindakan |
|---|---|---|
200 |
OK | Normal |
301/302 |
Redirect | Normal, cek jika redirect loop |
400 |
Bad Request | Error di request client |
401 |
Unauthorized | Auth gagal |
403 |
Forbidden | Permission denied |
404 |
Not Found | File/route tidak ada |
500 |
Internal Server Error | Error di aplikasi — investigasi! |
502 |
Bad Gateway | Container tidak respond — restart? |
503 |
Service Unavailable | Container down atau overload |
504 |
Gateway Timeout | Request terlalu lama diproses |
Pattern Log yang Normal vs Perlu Perhatian
Normal — Tidak Perlu Khawatir
404 dari scanner/bot:
"GET /robots.txt HTTP/1.1" 404
"GET /wp-admin/admin-ajax.php HTTP/1.1" 404
"GET /.env HTTP/1.1" 404
"GET /phpMyAdmin/ HTTP/1.1" 404
Scanner internet secara otomatis mencoba URL umum untuk mencari vulnerability. 404 untuk path ini adalah normal — artinya kamu tidak punya file yang mereka cari.
Health check:
"GET / HTTP/1.1" 200 60638 "-" "Uptime-Kuma/1.23.17"
"GET /health HTTP/1.1" 200 - "-" "kube-probe/1.27"
Log health check dari monitoring tool atau Kubernetes — sepenuhnya normal.
Static assets:
"GET /assets/app.js HTTP/1.1" 200 45231
"GET /favicon.ico HTTP/1.1" 200 1150
Normal, bisa diabaikan.
Perlu Perhatian — Investigasi
500 Internal Server Error:
[error] "POST /api/checkout HTTP/1.1" 500
Ada exception di kode — buka App logs untuk detail traceback.
502 Bad Gateway — berulang:
"GET / HTTP/1.1" 502
"GET / HTTP/1.1" 502
"GET / HTTP/1.1" 502
Container tidak bisa diakses — cek tab Metrics untuk Restarts, buka App logs untuk error.
504 Gateway Timeout:
"POST /api/process HTTP/1.1" 504
Request terlalu lama. Kemungkinan: query database lambat, external API timeout, atau infinite loop.
Spike 4xx/5xx tiba-tiba: Jika sebelumnya semua 200 lalu tiba-tiba banyak 5xx setelah deploy baru — kemungkinan bug di deployment terbaru. Cek App logs dan pertimbangkan rollback.
Cara Filter dan Search Logs
Filter per Pod
Untuk project dengan beberapa service (Laravel, PostgreSQL, Redis, Worker), filter logs per pod untuk fokus ke service yang bermasalah:
- Klik dropdown "All pods (N)"
- Pilih pod yang ingin dilihat
- Log langsung ter-filter
Search Keyword
Ketik di search bar untuk filter log yang mengandung keyword:
# Cari semua error
error
# Cari request ke endpoint tertentu
/api/users
# Cari user ID tertentu
user_id=12345
# Cari HTTP status tertentu
" 500 "
# Cari exception tertentu
TypeError
# Cari IP tertentu
10.42.4.44
Filter by Time Range
Klik time range selector (default "1 hour") untuk melihat log dari periode tertentu:
- 1 hour — debugging masalah baru
- 6 hours — investigasi masalah yang terjadi beberapa jam lalu
- 1 day — analisis pattern harian
Log history tersedia sesuai plan:
- Free: log terbatas
- Mekanik: 7 hari log history
- Pilot: 30 hari log history
- Enterprise: 90 hari log history
App Logs per Framework
Laravel
# Log di aplikasi
Log::info('User logged in', ['user_id' => $user->id]);
Log::error('Payment failed', ['order_id' => $order->id, 'error' => $e->getMessage()]);
Log::warning('Rate limit exceeded', ['ip' => $request->ip()]);
Laravel secara default menulis ke storage/logs/laravel.log. Di Helipod (container), log diarahkan ke stdout agar muncul di log viewer. Tambahkan di config/logging.php:
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['single', 'stderr'], // tambah stderr
'ignore_exceptions' => false,
],
'stderr' => [
'driver' => 'monolog',
'level' => env('LOG_LEVEL', 'debug'),
'handler' => StreamHandler::class,
'formatter' => env('LOG_STDERR_FORMATTER'),
'with' => [
'stream' => 'php://stderr',
],
],
],
Atau lebih simpel, set di .env:
LOG_CHANNEL=stderr
LOG_LEVEL=warning # hanya warning ke atas yang di-log di production
Django
import logging
logger = logging.getLogger(__name__)
# Di views.py
def checkout(request):
try:
# proses checkout
logger.info(f"Checkout success for user {request.user.id}")
except Exception as e:
logger.error(f"Checkout failed: {e}", exc_info=True)
return JsonResponse({'error': str(e)}, status=500)
Konfigurasi logging Django untuk stdout:
# settings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'verbose': {
'format': '{levelname} {asctime} {module} {message}',
'style': '{',
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'root': {
'handlers': ['console'],
'level': 'WARNING', # production: WARNING ke atas
},
'loggers': {
'django': {
'handlers': ['console'],
'level': os.getenv('DJANGO_LOG_LEVEL', 'WARNING'),
'propagate': False,
},
'myapp': {
'handlers': ['console'],
'level': 'INFO',
'propagate': False,
},
},
}
FastAPI / Flask
import logging
import sys
# Setup logging ke stdout
logging.basicConfig(
stream=sys.stdout,
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# Di route handler
@app.post("/api/checkout")
async def checkout(data: CheckoutSchema):
logger.info(f"Checkout initiated for user {data.user_id}")
try:
result = await process_checkout(data)
logger.info(f"Checkout success: {result.order_id}")
return result
except Exception as e:
logger.error(f"Checkout failed: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))
NestJS
import { Logger } from '@nestjs/common';
@Injectable()
export class CheckoutService {
private readonly logger = new Logger(CheckoutService.name);
async processCheckout(dto: CheckoutDto) {
this.logger.log(`Processing checkout for user ${dto.userId}`);
try {
const result = await this.paymentService.charge(dto);
this.logger.log(`Checkout success: order ${result.orderId}`);
return result;
} catch (error) {
this.logger.error(`Checkout failed: ${error.message}`, error.stack);
throw new InternalServerErrorException('Checkout failed');
}
}
}
NestJS secara default sudah output ke stdout — langsung muncul di log viewer Helipod.
Next.js
// Di server-side code (API routes, Server Components)
console.log('User authenticated:', userId);
console.error('Database query failed:', error);
// Atau gunakan library logging seperti pino
import pino from 'pino';
const logger = pino({ level: process.env.LOG_LEVEL || 'info' });
logger.info({ userId }, 'User authenticated');
logger.error({ error }, 'Database query failed');
Client-side logs (browser console) tidak muncul di Helipod logs — hanya server-side output yang ter-capture.
Structured Logging untuk Log yang Lebih Berguna
Log dalam format JSON (structured logging) jauh lebih mudah di-search dan di-parse:
Node.js dengan pino:
// src/logger.ts
import pino from 'pino';
export const logger = pino({
level: process.env.LOG_LEVEL || 'info',
formatters: {
level: (label) => ({ level: label }),
},
timestamp: pino.stdTimeFunctions.isoTime,
});
Output di logs Helipod:
{"level":"info","time":"2026-05-11T10:23:45.123Z","userId":123,"msg":"User logged in"}
{"level":"error","time":"2026-05-11T10:24:01.456Z","orderId":"ORD-456","error":"Payment gateway timeout","msg":"Checkout failed"}
Python dengan structlog:
import structlog
logger = structlog.get_logger()
logger.info("checkout_initiated", user_id=123, amount=150000)
logger.error("checkout_failed", user_id=123, error=str(e), order_id="ORD-456")
Output:
{"event": "checkout_initiated", "user_id": 123, "amount": 150000, "level": "info", "timestamp": "2026-05-11T10:23:45.123Z"}
Dengan structured logging, search di Helipod logs menjadi sangat powerful:
- Search
user_id=123→ semua aktivitas user 123 - Search
"level":"error"→ semua error - Search
checkout_failed→ semua kegagalan checkout
Strategi Debugging dengan Logs
Alur Debugging Umum
1. Buka halaman Logs global
2. Filter time range ke saat masalah terjadi
3. Search "error" atau " 5" (untuk 5xx)
4. Identifikasi pattern — error di service mana? Berapa sering?
5. Filter ke pod yang bermasalah
6. Baca konteks di sekitar error (log sebelum dan sesudahnya)
7. Jika butuh lebih detail → buka Terminal → debug langsung
Investigasi Insiden
Saat ada laporan dari user bahwa fitur X tidak bisa dipakai:
1. Tanya user: kapan persis error terjadi?
2. Buka Logs → set time range ke waktu tersebut
3. Search endpoint yang berkaitan: "/api/checkout"
4. Cari baris yang berwarna merah (error)
5. Baca error message dan traceback
6. Identifikasi root cause (database? external API? bug kode?)
7. Fix dan deploy
8. Verifikasi di Logs bahwa error tidak muncul lagi
Monitoring Setelah Deploy
Setiap kali deploy baru, buka Logs dengan time range "15 min" dan pantau:
- Apakah ada error baru yang tidak ada sebelumnya?
- Apakah response time (dari log) masih normal?
- Apakah ada 5xx yang meningkat?
Tips Penggunaan Logs yang Efektif
1. Log di level yang tepat:
DEBUG— detail untuk development, disable di productionINFO— event penting (user login, order created)WARNING— sesuatu yang tidak biasa tapi tidak crashERROR— error yang perlu investigasiCRITICAL— aplikasi tidak bisa berjalan
2. Include context di setiap log:
# Kurang berguna:
logger.error("Payment failed")
# Jauh lebih berguna:
logger.error("Payment failed", extra={
'user_id': user.id,
'order_id': order.id,
'amount': order.total,
'gateway': 'midtrans',
'error_code': e.code,
})
3. Jangan log data sensitif:
# JANGAN INI
logger.info(f"User login: email={email}, password={password}")
# Lakukan ini
logger.info(f"User login: email={email}")
4. Log request ID untuk tracing: Tambahkan unique request ID di setiap log entry agar mudah trace satu request dari awal sampai akhir.
5. Set LOG_LEVEL via environment variable:
LOG_LEVEL=warning # production: warning ke atas saja
Jangan log DEBUG di production — terlalu banyak noise dan bisa mengekspos informasi sensitif.
Kesimpulan
Log viewer di Helipod menghilangkan kebutuhan setup ELK stack, Datadog, atau tool log aggregation mahal untuk mendapatkan visibility ke aplikasi production. Filter per pod, search keyword, warna error yang mencolok — semua tersedia dari browser.
Yang terpenting: pastikan aplikasimu output log ke stdout (bukan hanya ke file), dan gunakan level logging yang tepat agar signal tidak tenggelam dalam noise.
Ingin tahu cara debug langsung ke dalam container? Baca Terminal Live di Helipod.
Ingin monitoring CPU dan memory? Baca Monitor Metrics di Helipod.
Punya pertanyaan? Hubungi kami di support@helipod.id atau bergabung ke komunitas di hangar.helipod.io.