Setup Logging & Monitoring Aplikasi Self-Hosted
Aplikasi kamu down jam 2 pagi. Kamu buka server, cek prosesnya sudah mati, tapi log-nya kosong. Atau lebih parah: log ada, tapi tersebar di lima file berbeda, formatnya campur aduk, dan kamu harus grep manual satu per satu sambil setengah sadar.
Ini bukan skenario hipotetikal. Ini yang terjadi kalau kamu deploy aplikasi self-hosted tanpa setup logging monitoring yang proper dari awal.
Artikel ini akan kasih kamu stack logging monitoring yang bisa jalan di VPS murah sekalipun — pakai Loki + Grafana + Promtail (stack PLG). Ringan, open-source, dan nggak butuh Elasticsearch yang rakus RAM.
Kenapa Stack Default Nggak Cukup
stdout dan file log mentah itu cukup untuk development. Tapi begitu aplikasi kamu di-deploy dan mulai ada traffic nyata, kamu butuh:
- Aggregasi — semua log dari semua service di satu tempat
- Search — bisa query log berdasarkan waktu, label, atau pattern
- Alerting — dikabarin sebelum user yang lapor duluan
- Retention — log lama dibuang otomatis biar disk nggak penuh
ELK Stack (Elasticsearch + Logstash + Kibana) bisa semua itu, tapi minimum RAM-nya 4GB hanya untuk Elasticsearch. Untuk VPS DigitalOcean atau Hetzner kelas $6–$10/bulan, itu terlalu boros.
Loki jauh lebih hemat karena dia cuma index label, bukan full-text index seperti Elasticsearch. Trade-off-nya: search harus pakai LogQL, bukan full-text search bebas. Untuk kebanyakan use case self-hosted, ini lebih dari cukup.
Arsitektur Stack yang Akan Kita Bangun
[Aplikasi kamu] --> stdout/file
|
[Promtail] <-- scrape log
|
[Loki] <-- store & index
|
[Grafana] <-- visualize & alert
Semua akan jalan via Docker Compose di satu VPS. Kalau kamu punya multiple server, Promtail bisa di-deploy di tiap server dan push ke satu Loki sentral.
Persiapan: Struktur Direktori
Buat struktur folder dulu sebelum nulis config apapun:
mkdir -p ~/monitoring/{loki,promtail,grafana}
cd ~/monitoring
Nanti akan ada tiga file config utama:
loki/loki-config.ymlpromtail/promtail-config.ymldocker-compose.yml
Step 1: Config Loki
Buat file loki/loki-config.yml:
auth_enabled: false
server:
http_listen_port: 3100
grpc_listen_port: 9096
common:
instance_addr: 127.0.0.1
path_prefix: /tmp/loki
storage:
filesystem:
chunks_directory: /tmp/loki/chunks
rules_directory: /tmp/loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemory
query_range:
results_cache:
cache:
embedded_cache:
enabled: true
max_size_mb: 100
schema_config:
configs:
- from: 2020-10-24
store: tsdb
object_store: filesystem
schema: v13
index:
prefix: index_
period: 24h
ruler:
alertmanager_url: http://localhost:9093
limits_config:
retention_period: 7d
compactor:
working_directory: /tmp/loki/retention
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
delete_request_store: filesystem
Satu hal penting: retention_period: 7d artinya log lebih dari 7 hari otomatis dihapus. Sesuaikan dengan kebutuhan dan kapasitas disk kamu. Kalau disk kamu kecil, turunkan ke 3d.
Step 2: Config Promtail
Promtail adalah agent yang scrape log dan kirim ke Loki. Buat promtail/promtail-config.yml:
server:
http_listen_port: 9080
grpc_listen_port: 0
positions:
filename: /tmp/positions.yaml
clients:
- url: http://loki:3100/loki/api/v1/push
scrape_configs:
- job_name: docker-containers
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 5s
relabel_configs:
- source_labels: ['__meta_docker_container_name']
regex: '/?(.*)'
target_label: 'container'
- source_labels: ['__meta_docker_container_log_stream']
target_label: 'logstream'
- source_labels: ['__meta_docker_container_label_com_docker_compose_service']
target_label: 'service'
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
__path__: /var/log/*.log
Config ini akan scrape semua container Docker secara otomatis plus system log di /var/log/. Kamu nggak perlu tambah config setiap kali deploy service baru.
Step 3: Docker Compose
Buat docker-compose.yml di root folder ~/monitoring/:
version: '3.8'
networks:
monitoring:
driver: bridge
volumes:
grafana-data:
services:
loki:
image: grafana/loki:2.9.0
ports:
- "3100:3100"
volumes:
- ./loki:/etc/loki
command: -config.file=/etc/loki/loki-config.yml
networks:
- monitoring
restart: unless-stopped
promtail:
image: grafana/promtail:2.9.0
volumes:
- /var/log:/var/log:ro
- /var/run/docker.sock:/var/run/docker.sock
- ./promtail:/etc/promtail
command: -config.file=/etc/promtail/promtail-config.yml
networks:
- monitoring
restart: unless-stopped
depends_on:
- loki
grafana:
image: grafana/grafana:10.2.0
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=gantipasswordini
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- grafana-data:/var/lib/grafana
networks:
- monitoring
restart: unless-stopped
depends_on:
- loki
Ganti gantipasswordini dengan password yang kuat. Jangan skip ini — Grafana yang exposed ke internet dengan password default adalah undangan buat dibobol.
Jalankan:
docker compose up -d
Cek semua container running:
docker compose ps
Step 4: Hubungkan Grafana ke Loki
- Buka browser, akses
http://IP-VPS-KAMU:3000 - Login dengan credential yang kamu set di compose file
- Pergi ke Connections → Data Sources → Add data source
- Pilih Loki
- Di field URL, isi:
http://loki:3100 - Klik Save & Test
Kalau muncul pesan "Data source connected and labels found", berarti Loki sudah terima log dari Promtail.
Sekarang coba query pertama kamu di Explore:
{job="varlogs"} |= "error"
Atau kalau mau lihat log dari container spesifik:
{container="nama-container-kamu"} | json | line_format "{{.message}}"
Gotcha yang Sering Bikin Stuck
1. Promtail nggak bisa akses Docker socket
Kalau log container nggak muncul, cek permission:
ls -la /var/run/docker.sock
# output: srw-rw---- 1 root docker ...
# Tambah user ke group docker, atau jalankan promtail sebagai root
docker compose logs promtail | grep -i error
Solusi paling cepat: tambah user: root di service promtail di compose file.
2. Loki reject log karena "out of order"
Ini terjadi kalau timestamp log kamu nggak monotonically increasing. Biasanya karena aplikasi nulis log dengan timestamp yang nggak konsisten. Tambahkan config ini di limits_config pada loki-config.yml:
limits_config:
ingestion_rate_mb: 16
ingestion_burst_size_mb: 32
allow_structured_metadata: false
reject_old_samples: true
reject_old_samples_max_age: 168h
3. Port 3000 dan 3100 exposed ke publik
Jangan biarkan port ini terbuka langsung ke internet tanpa auth. Pakai Nginx sebagai reverse proxy dengan basic auth minimal, atau gunakan Tailscale/Wireguard supaya hanya bisa diakses dari network kamu.
Contoh blok Nginx cepat:
server {
listen 80;
server_name monitoring.domainmu.com;
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
4. Disk penuh karena log explosion
Kalau ada bug yang bikin aplikasi kamu nulis ribuan baris log per detik, Loki bisa isi disk dalam hitungan jam. Pasang rate limit di Promtail:
# tambah di scrape_configs job kamu
pipeline_stages:
- limit:
rate: 1000
burst: 2000
drop: true
Bikin Alert Sederhana di Grafana
Setup monitoring tanpa alerting itu setengah-setengah. Buat alert basic untuk error rate:
- Buka Alerting → Alert Rules → New alert rule
- Di query, pakai LogQL:
sum(rate({container="aplikasi-kamu"} |= "ERROR" [5m])) > 10
Ini akan trigger kalau ada lebih dari 10 error per menit dalam 5 menit terakhir.
- Set Contact Point ke email atau Telegram (Grafana support keduanya native)
- Assign ke Notification Policy
Untuk Telegram, kamu butuh bot token dan chat ID. Masuk ke Alerting → Contact Points → Add contact point → Telegram, isi token dan chat ID, done.
Langkah Lanjutan
Setup logging monitoring aplikasi self-hosted dengan stack PLG ini sudah cukup untuk handle traffic ribuan request per hari di VPS kelas menengah. Ini yang gue lakuin setelah setup ini running:
-
Tambah metrics dengan Prometheus + Node Exporter — kalau kamu juga mau monitor CPU, RAM, dan disk usage (bukan hanya log), tambah Prometheus ke stack ini. Grafana sudah support keduanya sekaligus.
-
Buat dashboard custom — import dashboard ID
13639di Grafana untuk Docker monitoring siap pakai, lalu modifikasi sesuai kebutuhan. -
Backup Grafana dashboard — export dashboard kamu sebagai JSON dan simpan di Git. Jangan sampai konfigurasi dashboard hilang kalau VPS-nya harus di-rebuild.
-
Pisahkan monitoring stack ke VPS berbeda — kalau aplikasi utama kamu down, monitoring kamu juga ikut down kalau di server yang sama. Untuk production yang lebih serius, taruh stack PLG ini di VPS terpisah dan arahkan Promtail dari semua server ke sana.
Kalau kamu stuck di langkah mana pun, cek log Promtail dulu:
docker compose logs -f promtail
Hampir semua masalah koneksi dan permission akan kelihatan di sana.