ایک VPS پر self-hosted لاگ مینجمنٹ: RAM اور retention
ایک VPS پر لاگ مینجمنٹ کے لیے journald اور logrotate سے شروع کریں، پھر Loki یا OpenSearch چنیں؛ RAM کی کم از کم حد اور retention کے عملی اصول جانیں۔
ایک VPS پر self-hosted لاگ مینجمنٹ کی اصل لاگت
ایک VPS (virtual private server) پر self-hosted لاگ مینجمنٹ کا فیصلہ ایک بنیادی سوال پر منحصر ہے: کیا آپ کو search cluster درکار ہے، یا صرف log rotation اور grep کافی ہیں؟ زیادہ تر vendor guides اس سوال کا جواب ایک log line بھی وصول ہونے سے پہلے 3 nodes اور 12 GB RAM سے شروع کرتی ہیں۔ ایک سرور پر یہ جواب مفید نہیں، اس لیے ذیل کا موازنہ اس بنیاد پر ہے کہ ہر اختیار کسی چھوٹے سرور سے لاگز محفوظ کرنے سے پہلے کیا تقاضے کرتا ہے۔
اگر آپ 1 یا 2 سرور چلاتے ہیں اور یہ جاننا چاہتے ہیں کہ گزشتہ Tuesday کو کیا ہوا تھا، تو systemd-journald اور logrotate پہلے ہی یہ کام کر دیتے ہیں، اور آپ اگلے section کے بعد رک سکتے ہیں۔ اگر کئی مشینوں کے لاگز ایک جگہ جمع کرنا ہوں اور کئی ہفتوں کے لاگز میں search درکار ہو، تو Grafana Loki چھوٹے سرور کے لیے موزوں ہے، کیونکہ یہ لاگ lines کے متن کے بجائے labels کو index کرتا ہے۔ Elasticsearch اور OpenSearch آپ کو حقیقی full text search دیتے ہیں، لیکن اس کے لیے memory درکار ہوتی ہے، کیونکہ JVM (Java virtual machine) heap کی ایک کم از کم حد ہوتی ہے جس سے نیچے نہیں جایا جا سکتا۔
journald سے شروع کریں، کیونکہ زیادہ تر لوگ یہیں رک جاتے ہیں
systemd-journald ہر موجودہ Ubuntu یا Debian سرور پر پہلے سے چل رہا ہوتا ہے۔ یہ ہر service unit کا standard output، kernel messages، اور syslog کو بھیجی گئی تمام معلومات محفوظ کرتا ہے۔ زیادہ تر incidents کے لیے چار commands کافی ہوتی ہیں۔
journalctl -u nginx.service --since "2026-08-14 09:00" --until "2026-08-14 10:00"
journalctl -p err -b
journalctl -f -u ssh.service
journalctl --disk-usageآخری command Archived and active journals take up 1.1G in the file system. جیسی ایک line دکھاتی ہے۔ یہی وہ number ہے جو طے کرتا ہے کہ آپ کو مزید کچھ درکار ہے یا نہیں۔ اگر یہ چند سو megabytes دکھائے اور آپ -u اور --since سے مطلوبہ معلومات تلاش کر سکیں، تو کام مکمل ہے۔
journal کے reboot کے بعد محفوظ رہنے کا انحصار Storage= اور اس بات پر ہے کہ /var/log/journal موجود ہے یا نہیں۔ عام Storage=auto setting کے ساتھ journald اس وقت /var/log/journal میں لکھتا ہے جب وہ directory موجود ہو، اور اس کے نہ ہونے پر /run/log/journal میں لکھتا ہے۔ /run memory backed ہے، اس لیے اس directory کے بغیر machine پر reboot کے وقت ہر log مٹ جاتا ہے۔ یہی وہ وقت ہوتا ہے جب آپ کو یہ logs پڑھنے کی ضرورت ہوتی ہے۔ Ubuntu images میں یہ directory شامل ہوتی ہے۔ Minimal اور container based images میں اکثر یہ موجود نہیں ہوتی۔
ls -d /var/log/journal
sudo mkdir -p /var/log/journal
sudo systemctl restart systemd-journald
journalctl --disk-usagerestart کے بعد journalctl --disk-usage کو /var/log/journal سے کم size رپورٹ کرنا چاہیے، نہ کہ /run سے۔ Defaults پہلے ہی محدود ہوتے ہیں، اور یہی بنیادی وجہ ہے کہ journald ایک قابل اعتماد حل ہے، محض fallback نہیں۔ journald.conf man page SystemMaxUse= کو file system size کے 10% اور SystemKeepFree= کو 15% پر set کرتی ہے، اور ہر calculated default کو 4G تک محدود رکھتی ہے۔ SystemMaxFileSize= کی default value SystemMaxUse= کی ایک آٹھویں حصے کے برابر ہے، جس کی زیادہ سے زیادہ حد 128M ہے۔ اس طرح عموماً سات rotated files محفوظ رہتی ہیں۔ MaxRetentionSec= کی default value 0 ہے، جس سے عمر کی بنیاد پر deletion بند رہتی ہے۔ اس آخری default کو دوبارہ دیکھیں: ابتدائی configuration میں journal صرف size سے محدود ہوتا ہے، age سے کبھی نہیں۔
[Journal]
Storage=persistent
SystemMaxUse=2G
MaxRetentionSec=30dayیہ configuration /etc/systemd/journald.conf.d/99-size.conf میں لکھیں، journald کو restart کریں، پھر تصدیق کریں کہ journalctl --disk-usage نئی ceiling کی طرف بڑھ گئی ہے۔ اگلی rotation کا انتظار کیے بغیر ابھی space واپس حاصل کرنے کے لیے sudo journalctl --vacuum-size=500M یا sudo journalctl --vacuum-time=14d چلائیں۔ دونوں commands حذف کی جانے والی ہر file دکھاتی ہیں، اس لیے خاموش execution کا مطلب ہے کہ حذف کرنے کے لیے کچھ موجود نہیں تھا۔
journal سے باہر کی ہر چیز، مثلاً /var/log/nginx/access.log، logrotate کی ذمہ داری ہے، اور یہ systemd timer کے ذریعے روزانہ چلتا ہے۔ ایک failure کو سمجھنا ضروری ہے، کیونکہ یہ df میں bug جیسا دکھائی دیتا ہے۔ rotation کے بعد پرانی file directory listing سے غائب ہو جاتی ہے، جبکہ daemon اسے اب بھی open رکھتا ہے۔ اس لیے df -h disk کو full دکھاتا ہے، جبکہ du -sh /var/log اس سے کہیں کم space دکھاتا ہے۔ Space صرف اس وقت واپس آتی ہے جب process اپنا log دوبارہ open کرتا ہے۔ Configuration میں موجود postrotate reload line اسی مقصد کے لیے ہے۔ sudo lsof -nP +L1 ان deleted files کی فہرست دکھاتا ہے جو اب بھی open ہیں، اور ہر file کو open رکھنے والے process کا نام بھی بتاتا ہے۔ کسی چیز کو تبدیل کیے بغیر rule کی جانچ sudo logrotate -d /etc/logrotate.d/nginx سے کریں۔
متعدد سرورز سے ایک collector کو logs بھیجنا
جب ایک سے زیادہ سرور ہوں تو متعدد Linux سرورز کا بیک وقت انتظام اس وقت آسان ہو جاتا ہے جب ان کے logs ایک ہی جگہ پہنچیں۔ زیادہ تر distributions میں rsyslog پہلے سے installed ہوتا ہے، اس لیے سب سے کم لاگت والا مرکزی collector ہر sender پر ایک file ہے۔
*.* action(type="omfwd" target="logs.example.com" port="514" protocol="tcp")اسے /etc/rsyslog.d/50-forward.conf کے طور پر محفوظ کریں، پھر sudo rsyslogd -N1 سے اس کی جانچ کریں۔ یہ configuration کو validate کرتا ہے اور کچھ شروع کیے بغیر exit ہو جاتا ہے۔ اس کے بعد rsyslog کو restart کریں۔ collector پر TCP input کو enable کریں۔
module(load="imtcp")
input(type="imtcp" port="514")دو انتباہات ہیں، اور دونوں عملی نوعیت کے ہیں۔ سادہ syslog میں encryption اور authentication نہیں ہوتی، اس لیے port 514 تک رسائی رکھنے والا کوئی بھی فریق ایسی log lines داخل کر سکتا ہے جو بالکل آپ کی lines جیسی نظر آئیں۔ اسے private network یا VPN سے bind کریں اور اس port پر firewall لگائیں۔ دوسرا مسئلہ یہ ہے کہ default action queue memory میں رہتی ہے۔ جب collector قابل رسائی نہ ہو تو queue بھر جاتی ہے اور messages ضائع ہو جاتے ہیں؛ ان کی کوئی copy محفوظ نہیں رہتی۔ rsyslog اس صورت کے لیے disk assisted queue کو اپنی قابل اعتماد forwarding tutorial میں document کرتا ہے۔
چھوٹے VPS کے لیے ELK stack موزوں کیوں نہیں
ELK سے مراد storage اور search کے لیے Elasticsearch، ingestion pipeline کے لیے Logstash، اور interface کے لیے Kibana ہے۔ کم از کم ضرورت JVM heap ہے، اور کوئی بھی log آنے سے پہلے یہ memory مقرر کر دی جاتی ہے۔
Elastic کی documentation کے مطابق ہر Elasticsearch node کے لیے heap کو دستیاب total memory کے 50% سے زیادہ نہ رکھیں، کیونکہ process off heap buffers بھی استعمال کرتا ہے اور index files کو تیزی سے پڑھنے کے لیے operating system file cache پر انحصار کرتا ہے۔ اس لیے 2 GB heap کے لیے Kibana سے پہلے ہی 4 GB machine درکار ہوتی ہے، اور اس کام کے لیے درکار memory اس کے علاوہ ہے جس کے لیے server خریدا گیا تھا۔ Elastic یہ بھی بتاتا ہے کہ Elasticsearch node کے roles اور total memory کی بنیاد پر heap خودکار طور پر مقرر کرتا ہے۔ اس کا مطلب ہے کہ چھوٹی machine کو چھوٹا heap ملتا ہے، اور پھر وہ اپنا زیادہ وقت garbage collection میں صرف کرتی ہے۔
Logstash وہ جزو ہے جو چھوٹے budget کو براہ راست ناکافی بنا دیتا ہے۔ Elastic کی اپنی JVM settings page عام ingestion کے لیے کم از کم 4GB اور زیادہ سے زیادہ 8GB heap تجویز کرتی ہے۔ 4 GB VPS کی پوری memory pipeline کے درمیان موجود ایک process کے لیے صرف ہو جاتی ہے۔
The data behind this chart
[
{
"label": "Loki plus Alloy (no JVM)",
"documented_heap_mb": 0
},
{
"label": "OpenSearch demo compose",
"documented_heap_mb": 512
},
{
"label": "OpenSearch production example",
"documented_heap_mb": 2048
},
{
"label": "Logstash recommended minimum",
"documented_heap_mb": 4096
}
]یہ وہ values ہیں جو ہر project اپنی documentation میں خود شائع کرتا ہے۔ یہ کسی test box پر کی گئی measurements نہیں ہیں، اور آپ کا workload ان values کو بدل سکتا ہے۔ OpenSearch کی sample compose file demo کے لیے فی node 512 MB اور production example میں 2048 MB مقرر کرتی ہے، جبکہ Logstash کی تجویز کردہ lower bound 4096 MB ہے۔ Loki اور Alloy کے لیے heap column 0 دکھاتا ہے، کیونکہ یہ Go programs ہیں اور ان کے لیے JVM heap reserve کرنے کی ضرورت نہیں ہوتی۔ پورا فرق ایک number میں واضح ہے: JVM component یہ memory reserve کرتا ہے، چاہے کوئی log آئے یا نہ آئے۔
اگر آپ پھر بھی ایک چھوٹے server پر Elastic stack چلانا چاہتے ہیں تو Logstash ہٹا دیں اور کسی light collector کے ذریعے logs براہ راست Elasticsearch میں بھیجیں۔ Logstash بڑی مقدار میں data parse اور transform کرنے کے لیے موجود ہے، جبکہ ایک ہی machine پر یہ کام edge پر کیا جا سکتا ہے یا اسے چھوڑا جا سکتا ہے۔
Elasticsearch اور OpenSearch دونوں کے لیے vm.max_map_count کو 262144 تک بڑھانا بھی ضروری ہے، کیونکہ یہ index files کو memory map کرتے ہیں اور Linux کی default limit ان کے لیے بہت کم ہے۔ نئی machine پر startup کے چند seconds بعد exit ہونے والا container عموماً اسی مسئلے کی وجہ سے ہوتا ہے، کسی اور وجہ سے نہیں۔
OpenSearch یا Elasticsearch: آپ کون سا deploy کر سکتے ہیں؟
مختصر license history یہ ہے، کیونکہ اسی سے طے ہوتا ہے کہ آپ کو کیا چلانے کی اجازت ہے۔ January 2021 میں Elastic نے Elasticsearch اور Kibana کو Apache 2.0 سے ہٹا کر dual SSPL (server side public license) اور Elastic License 2.0 model کے تحت جاری کیا۔ AWS نے آخری Apache 2.0 code کو fork کر کے OpenSearch بنایا، جو Apache 2.0 پر برقرار ہے۔ September 2024 میں Elastic نے free source code کے لیے ایک اور option کے طور پر AGPLv3 (GNU Affero General Public License version 3) شامل کیا۔ ایک VPS پر ایک شخص کی self-hosting کے لیے ان میں سے ہر license آپ کے موجودہ استعمال کی اجازت دیتا ہے۔ یہ licenses اس وقت اہم ہو جاتے ہیں جب آپ software دوسرے لوگوں کو managed service کے طور پر فراہم کریں۔
چھوٹے server پر عملی فرق اس history کے مقابلے میں کم ہے، کیونکہ دونوں کے اندر بنیادی engine ایک ہی ہے۔ نام مختلف ہیں: OpenSearch میں index lifecycle کو ISM (index state management) اور Elasticsearch میں ILM (index lifecycle management) کہا جاتا ہے۔ August 2026 تک OpenSearch 2.12 اور بعد کے versions پہلی بار run ہونے پر admin password set کیے بغیر start نہیں ہوتے۔
sudo sysctl -w vm.max_map_count=262144
printf 'vm.max_map_count = 262144\n' | sudo tee /etc/sysctl.d/99-opensearch.conf
docker run -d -p 9200:9200 -p 9600:9600 -e "discovery.type=single-node" \
-e "OPENSEARCH_INITIAL_ADMIN_PASSWORD=<custom-admin-password>" \
opensearchproject/opensearch:latestsysctl -w والی line setting کو ابھی نافذ کرتی ہے، جبکہ /etc/sysctl.d/ میں موجود file وہ حصہ ہے جو reboot کے بعد بھی برقرار رہتا ہے۔ curl -k -u admin:<password> https://localhost:9200 سے تصدیق کریں کہ container start ہو گیا ہے۔ یہ demo certificate استعمال کرتے ہوئے https پر جواب دیتا ہے، اس لیے -k verification کو skip کرتا ہے، اور صحت مند جواب ایک چھوٹا JSON block ہوتا ہے جس میں cluster اور version کے نام درج ہوتے ہیں۔ OpenSearch install page Docker Desktop users کو یہ بھی بتاتا ہے کہ host کو کم از کم 4 GB memory فراہم کریں۔ اس سے اندازہ ہوتا ہے کہ process کو کتنے resources درکار ہیں۔
Loki کو چھوٹا کیسے رکھا جاتا ہے: مکمل text index کے بجائے labels
Loki، labels پر ایک index رکھتا ہے اور log lines کو compressed chunks کی صورت میں محفوظ کرتا ہے۔ Query پہلے streams منتخب کرتی ہے اور پھر text کو filter کرتی ہے۔ {unit="ssh.service"} |= "Failed password" اپنے label کے ذریعے stream منتخب کرتا ہے، پھر اس string کے لیے ان chunks کو scan کرتا ہے۔ کسی line کے body کو index نہیں کیا جاتا، اس لیے ingestion کم لاگت رہتی ہے اور memory میں رکھنے کے لیے inverted index موجود نہیں ہوتا۔ لاگت query کے وقت منتقل ہو جاتی ہے، اور یہ اس وقت اچھا تبادلہ ہے جب عموماً معلوم ہو کہ آپ کس service کا جائزہ لے رہے ہیں۔
Grafana کی documentation کے مطابق monolithic mode، یعنی -target=all کے ساتھ تمام Loki کا ایک process میں چلنا، تقریباً 20GB فی دن تک کے کم read اور write volumes کے لیے موزوں ہے۔ ایک VPS اس حد سے کافی کم رہتا ہے۔
اصل مسئلہ label cardinality ہے۔ label values کا ہر منفرد combination ایک stream ہوتا ہے، اور streams کی تعداد Loki کی memory اور index size کو بڑھاتی ہے۔ client IP address یا request identifier رکھنے والا label ہر value کے لیے ایک stream بناتا ہے۔ اس طرح مصروف web server ایک دن میں دسیوں ہزار streams پیدا کر سکتا ہے، اور process اس وقت تک بڑھتا رہتا ہے جب تک kernel اسے روک نہیں دیتا۔ labels کو ان values تک محدود رکھیں جنہیں آپ کاغذ پر گن سکتے ہوں: unit، host، job، level۔ متغیر تفصیل line کے اندر رکھیں، جہاں query کے وقت filter expression اسے تلاش کر سکے۔
ایک VPS پر Loki اور Alloy انسٹال کریں
یہ کام دو processes انجام دیتے ہیں۔ Loki logs محفوظ کرتا ہے اور queries کے جواب دیتا ہے۔ Grafana Alloy logs پڑھ کر انہیں آگے بھیجتا ہے۔ پہلے logs بھیجنے کے لیے Promtail استعمال ہوتا تھا، لیکن یہ 2 March 2026 کو end of life ہو گیا۔ اس لیے نئی installations میں Alloy استعمال ہوتا ہے، اور Loki کی اپنی Docker مثال میں بھی اب Alloy configuration شامل ہوتی ہے۔
wget https://raw.githubusercontent.com/grafana/loki/v3.7.0/cmd/loki/loki-local-config.yaml -O loki-config.yamlاستعمال سے پہلے اس file کو پڑھیں۔ یہ path_prefix: /tmp/loki کو /tmp/loki/chunks کے اندر chunks کے ساتھ set کرتی ہے۔ Demo کے لیے یہ درست ہے، لیکن server کے لیے غلط ہے۔ Container کے /tmp کے اندر موجود کوئی بھی چیز container دوبارہ بننے کے بعد محفوظ نہیں رہتی۔ اس لیے اگلی image update پر آپ کی history ختم ہو جائے گی۔ اسے ایسی path پر point کریں جسے آپ mount کرتے ہوں۔
common:
instance_addr: 127.0.0.1
path_prefix: /loki
storage:
filesystem:
chunks_directory: /loki/chunks
rules_directory: /loki/rules
replication_factor: 1
ring:
kvstore:
store: inmemorydocker volume create loki-data
docker run --name loki -d \
-v $(pwd):/mnt/config -v loki-data:/loki \
-p 127.0.0.1:3100:3100 \
grafana/loki:3.7.0 -config.file=/mnt/config/loki-config.yaml
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:3100/readyآخری command کو 200 دکھانا چاہیے، کیونکہ Loki کے requests قبول کرنے کے لیے تیار ہونے کے بعد /ready HTTP 200 واپس کرتا ہے۔ کوئی اور نتیجہ اس بات کی علامت ہے کہ process ابھی start ہو رہا ہے یا configuration reject ہو گئی ہے۔ docker logs loki وجہ بتاتا ہے۔ run command میں دو تفصیلات جان بوجھ کر رکھی گئی ہیں۔ Port صرف 127.0.0.1 پر publish کیا گیا ہے، کیونکہ sample configuration میں auth_enabled: false موجود ہے اور Loki اپنی user authentication فراہم نہیں کرتا۔ اس لیے جو بھی port 3100 تک پہنچ سکتا ہے، وہ ہر log پڑھ سکتا ہے اور جعلی logs لکھ سکتا ہے۔ اسے loopback پر رکھیں، یا VPN یا authentication والے reverse proxy کے پیچھے رکھیں۔ Named volume بھی اہم ہے، کیونکہ image loki user کے طور پر UID 10001 کے ساتھ چلتی ہے۔ اس لیے root کی ملکیت والی bind-mounted host directory میں container لکھ نہیں سکتا۔
sudo apt-get update && sudo apt-get install -y gpg wget
sudo mkdir -p /etc/apt/keyrings/
sudo wget -O /etc/apt/keyrings/grafana.asc https://apt.grafana.com/gpg-full.key
echo "deb [signed-by=/etc/apt/keyrings/grafana.asc] https://apt.grafana.com stable main" \
| sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install -y alloyAlloy /etc/alloy/config.alloy پڑھتا ہے۔ یہ configuration system journal اور files کے ایک set سے logs پڑھ کر دونوں کو local Loki پر بھیجتی ہے۔
loki.write "local" {
endpoint {
url = "http://127.0.0.1:3100/loki/api/v1/push"
}
}
loki.relabel "journal" {
forward_to = []
rule {
source_labels = ["__journal__systemd_unit"]
target_label = "unit"
}
}
loki.source.journal "read" {
forward_to = [loki.write.local.receiver]
relabel_rules = loki.relabel.journal.rules
labels = {job = "systemd-journal", host = "app-01"}
}
local.file_match "nginx" {
path_targets = [{"__path__" = "/var/log/nginx/*.log", "job" = "nginx", "host" = "app-01"}]
}
loki.source.file "nginx" {
targets = local.file_match.nginx.targets
forward_to = [loki.write.local.receiver]
}Relabel rule journal کے __journal__systemd_unit field کو unit نام کے label میں copy کرتا ہے۔ بعد میں {unit="ssh.service"} کے کام کرنے کی وجہ یہی ہے۔ اس rule کے بغیر unit name entry کے اندر رہتا ہے، label میں نہیں آتا۔ اس لیے آپ unit name کے مطابق selection نہیں کر سکتے اور ہر query کو تمام entries scan کرنا پڑتی ہیں۔
sudo systemctl reload alloy
systemctl show -p User alloy
sudo journalctl -n 5
sudo -u alloy journalctl -n 5زیادہ تر setups اسی مرحلے پر رک جاتے ہیں۔ Alloy اپنی service account کے طور پر چلتا ہے، root کے طور پر نہیں۔ System journal پڑھنے کے لیے systemd-journal group کی رکنیت درکار ہے، جبکہ Debian اور Ubuntu میں /var/log/nginx کے اندر موجود files، adm group کی ملکیت ہوتی ہیں۔ آخری command میں وہ account استعمال کریں جو systemctl show نے دکھایا تھا۔ اگر اس کا نتیجہ root کے طور پر چلانے کے مقابلے میں بہت کم entries واپس کرے تو اس account کو system journal پڑھنے کی اجازت نہیں ہے۔ ایسی صورت میں configuration درست ہونے کے باوجود Loki خالی رہے گا۔ Groups شامل کریں، پھر sudo usermod -aG systemd-journal,adm alloy کے بعد sudo systemctl restart alloy کے ذریعے service restart کریں۔
curl -G -s "http://127.0.0.1:3100/loki/api/v1/query_range" \
--data-urlencode 'query={job="systemd-journal"}' \
--data-urlencode 'limit=5' | jq '.data.result | length'0 سے بڑی تعداد کا مطلب ہے کہ اس label کے ساتھ streams موجود ہیں اور ان میں entries ہیں۔ 0 کا مطلب ہے کہ اس label کے تحت ابھی کچھ موصول نہیں ہوا۔ ایک default عام false alarm کی وضاحت کرتا ہے: loki.source.journal، max_age کو 7h پر set کرتا ہے۔ اس لیے fresh start journal کے آخری سات گھنٹے پڑھتا ہے، اور اس سے پرانا کوئی data نہیں پڑھتا۔ Human interface کے لیے اسی box پر Grafana چلائیں اور Loki data source کو http://127.0.0.1:3100. پر point کریں۔ Container logs کے لیے مختلف source درکار ہے: Alloy چلنے والے Docker containers کو discover کرکے ان کے logs پڑھتا ہے۔ Loki کی اپنی getting started مثال بھی یہی طریقہ استعمال کرتی ہے۔ ایک VPS پر single node k3s cluster میں یہی job pod log directory پر منتقل ہو جاتی ہے، جس میں kubelet logs لکھتا ہے۔
Retention: وہ دن منتخب کریں جس دن logs ختم ہوں
تقریباً کوئی بھی شخص disk بھرنے تک retention period منتخب نہیں کرتا، اور پھر اسے صبح 3 بجے service بند ہونے کے دوران منتخب کرتا ہے۔ پہلے دن ہی دو سوالات کی بنیاد پر فیصلہ کریں: آپ حقیقتاً کتنے عرصے پرانے logs دیکھتے ہیں، اور اگلے ماہ incident review کے دوران آپ کے پاس کیا موجود ہونا ضروری ہے۔ ایک single server کے لیے 14 سے 30 دن دونوں سوالات کا جواب دیتے ہیں۔
Loki compactor enable کرنے تک کچھ بھی delete نہیں کرتا۔ Retention بطور default بند ہوتی ہے۔ یہ ان لوگوں کے لیے حیرت کا باعث بنتا ہے جن کا volume بھر گیا، جبکہ retention_period configuration میں موجود رہ کر کچھ نہیں کر رہا تھا۔
limits_config:
retention_period: 744h
compactor:
working_directory: /loki/retention
compaction_interval: 10m
retention_enabled: true
retention_delete_delay: 2h
retention_delete_worker_count: 150
delete_request_store: filesystem744h، 31 دن ہوتے ہیں۔ اس block پر چار documented rules لاگو ہوتے ہیں:
- Retention compactor کے ذریعے نافذ ہوتی ہے، اور Grafana کی documentation کے مطابق compactor کو single instance کے طور پر چلانا چاہیے۔ ایک VPS پر یہ خود بخود ہو جاتا ہے۔
- کم از کم retention period 24h ہے، اور retention صرف اسی وقت کام کرتی ہے جب index period 24h ہو۔ نمونہ
schema_configپہلے ہیperiod: 24hاستعمال کرتا ہے، اس لیے اسے تبدیل نہ کریں۔ retention_enabledکے true ہونے کے بعدdelete_request_storeضروری ہے۔ یہ اس store کا نام بتاتا ہے جہاں delete requests رکھی جاتی ہیں۔ Filesystem-backed single node میں یہ schema میں پہلے سے موجودobject_store: filesystemسے مطابقت رکھتا ہے۔- Chunks کو پہلے mark کیا جاتا ہے اور
retention_delete_delayکے بعد remove کیا جاتا ہے۔ یہاں یہ مدت 2h ہے، اس لیے free space policy میں بیان کردہ وقت کے بعد واپس آتی ہے۔ Reload کے پانچ منٹ بعدdfدیکھ کر setting کا فیصلہ نہ کریں۔
OpenSearch پوری indexes کو delete کرتا ہے، انفرادی lines کو نہیں۔ اسی لیے log indexes روزانہ بنائی جاتی ہیں۔ ISM policy کسی index کو مختلف states کے ذریعے منتقل کرتی ہے اور اس کے کافی پرانا ہونے پر اسے delete کر دیتی ہے۔ ایک ism_template نئی indexes پر یہ policy لاگو کرتا ہے، اس لیے آپ کو یہ کام ہر بار یاد رکھنے کی ضرورت نہیں رہتی۔
وہ ISM policy جو 14 دن بعد log indexes delete کرتی ہے
{
"policy": {
"description": "delete log indexes after 14 days",
"default_state": "hot",
"states": [
{
"name": "hot",
"actions": [],
"transitions": [
{ "state_name": "delete", "conditions": { "min_index_age": "14d" } }
]
},
{
"name": "delete",
"actions": [ { "delete": {} } ],
"transitions": []
}
],
"ism_template": { "index_patterns": ["logs-*"], "priority": 100 }
}
}اسے _plugins/_ism/policies/logs-retention کو PUT بھیج کر بنائیں۔ Template ان indexes پر لاگو ہوتا ہے جو policy کے موجود ہونے کے بعد بنائی جائیں۔ اس لیے disk پر پہلے سے موجود ہر چیز پر policy دستی طور پر attach کرنی ہوگی۔
آپ جو بھی system چلائیں، retention number اتنا ہی مؤثر ہے جتنا اس کے پیچھے موجود free space check۔ اگر volume میں logs کے 10 دن پہلے ہی بھر چکے ہوں تو 14 دن بعد deletion آپ کو نہیں بچائے گی۔ اس لیے policy کو VPS پر disk health monitoring کے ساتھ استعمال کریں اور 80% استعمال ہونے پر alert configure کریں۔
لاگز کے فی GB کے لیے کتنی ڈسک درکار ہے
ایمان دارانہ جواب یہ ہے کہ مقدار آپ کی log lines اور fields پر منحصر ہے۔ اس لیے کسی شائع شدہ تناسب پر بھروسا کرنے کے بجائے اپنے data پر پیمائش کریں۔ دونوں mechanisms کا اثر مختلف ہے، اس لیے سمت کا اندازہ لگایا جا سکتا ہے۔ OpenSearch اور Elasticsearch ہر indexed field کے لیے stored document کے ساتھ inverted index لکھتے ہیں۔ اس لیے ڈسک پر محفوظ ہونے والا data raw text سے زیادہ ہوتا ہے، اور ہر replica اس مقدار کو بڑھا دیتا ہے۔ Single-node setup میں replica count کو 0 رکھیں، کیونکہ اسی node پر موجود replica shard اس node کے fail ہونے سے محفوظ نہیں رہ سکتا۔ اسے 1 پر چھوڑنے سے ڈسک کا استعمال دوگنا ہو جاتا ہے اور cluster health ہمیشہ کے لیے yellow رہتی ہے۔ Loki compressed chunks اور ایک چھوٹا label index لکھتا ہے، اس لیے اس کا disk footprint lines کے compressed size کے مطابق بڑھتا ہے۔
sudo du -sh /var/lib/docker/volumes/loki-data/_data
curl -k -u admin:<password> "https://localhost:9200/_cat/indices?v&h=index,docs.count,store.size"جو طریقہ آپ کے setup پر لاگو ہو، اسے مسلسل دو دن چلائیں۔ دونوں پیمائشوں کا فرق آپ کی روزانہ کی growth ہے۔ اسے اپنی retention days سے ضرب دیں، پھر compaction اور merges کے لیے تقریباً 30% اضافی گنجائش شامل کریں، اور نتیجے کا volume کے ساتھ موازنہ کریں۔ اگر یہ مقدار volume میں نہیں آتی تو نئی ڈسک خریدنے سے پہلے retention کم کریں، کیونکہ بڑا volume اسی مسئلے کو صرف چند ہفتوں کے لیے مؤخر کرے گا۔
چھوٹے سرور پر سب سے پہلے کیا خراب ہوتا ہے
Memory سب سے پہلے ختم ہوتی ہے۔ kernel کا OOM (out of memory) killer کسی بڑے process کو منتخب کرتا ہے، اور logging box پر سب سے بڑا process JVM ہوتا ہے۔ journalctl -k | grep -i "killed process" میں brackets کے اندر process name کے ساتھ دکھایا جاتا ہے کہ process کو terminate کیا گیا۔ متاثرہ process ہمیشہ log stack نہیں ہوتا؛ sshd یا آپ کا database بھی منتخب ہو سکتا ہے۔ اسی طرح logging کا تجربہ اس application کو بند کر سکتا ہے جس سے آپ logs حاصل کرنا چاہتے تھے۔ containers کے لیے واضح limits مقرر کریں تاکہ failure اسی جگہ ہو جہاں آپ نے اسے مقرر کیا ہے۔ Docker Compose میں memory limits اسی مقصد کے لیے ہیں۔
Disk دوسری بڑی وجہ ہے، اور search engines ایک مخصوص اور قابل شناخت انداز میں fail ہوتے ہیں۔ Elasticsearch اور OpenSearch disk usage کو کئی سطحوں پر monitor کرتے ہیں۔ low watermark 85% اور high watermark 90% پر ہوتا ہے۔ flood stage 95% پر پہنچنے کے بعد، اس node پر shard رکھنے والے ہر index کو block index.blocks.read_only_allow_delete مل جاتا ہے، اور اس کے بعد writes blocked by: [FORBIDDEN/12/index read-only / allow delete (api)] کے ساتھ fail ہوتی ہیں۔ usage دوبارہ high watermark سے کم ہونے پر block ختم ہو جاتا ہے۔ پہلے خالی جگہ بنائیں، پھر block برقرار رہنے کی صورت میں ہی اسے دستی طور پر clear کریں۔
curl -k -u admin:<password> -X PUT "https://localhost:9200/_all/_settings" \
-H 'Content-Type: application/json' \
-d '{"index.blocks.read_only_allow_delete": null}'Loki زیادہ خاموشی سے fail ہوتا ہے۔ اس میں read-only mode نہیں ہوتا جس میں یہ منتقل ہو سکے، اس لیے full volume sender پر failed pushes اور query results میں gaps کی صورت میں ظاہر ہوتا ہے۔ cardinality کا مسئلہ error کے بجائے memory کے بتدریج بڑھنے کی صورت میں سامنے آتا ہے۔ chunks directory کا size کسی incident کے بعد نہیں بلکہ مقررہ schedule کے مطابق monitor کریں۔
آخری failure غلط data داخل کرنے سے ہوتا ہے۔ log system، metrics system نہیں ہے۔ ہر 10 seconds بعد sampled CPU load کو text کے طور پر محفوظ کرنا مہنگا ہوتا ہے اور اسے graph کرنا بھی مشکل ہوتا ہے۔ یہ کام Ubuntu 24.04 پر Zabbix monitoring server جیسے نظام کا ہے۔ Application exceptions کے لیے grouping، deduplication اور stack trace view درکار ہوتے ہیں، اور یہ کام self-hosted error tracker کا ہے۔ یہ معلوم کرنا کہ site مکمل طور پر down ہے، ایک الگ کام ہے۔ اس کے لیے Uptime Kuma جیسا uptime اور status page استعمال کیا جاتا ہے۔ log system کو ایسی text lines کے لیے رکھیں جنہیں کوئی شخص پڑھے۔
FAQ
کیا اپنے سرور logs کو search کرنے کے لیے Elasticsearch درکار ہے؟
ایک یا دو سرورز کے لیے نہیں۔ journalctl پہلے ہی unit، priority، boot اور time range کے مطابق filtering کرتا ہے، جبکہ rotated files grep اور zgrep کے مطابق جواب دیتی ہیں۔ Search cluster اس وقت اپنی memory کا جواز پیدا کرتا ہے جب آپ کے پاس متعدد machines ہوں، جب آپ کو ان سب میں بیک وقت free text search درکار ہو، یا جب کئی افراد کو مشترکہ interface استعمال کرنا ہو۔ اس سے کم پیمانے پر size limit اور retention time کے ساتھ journald اضافی RAM کے بغیر یہی کام کرتا ہے۔
self-hosted log management کے لیے کتنی RAM درکار ہے؟
عام اندازے کے بجائے ہر project کی شائع کردہ figures استعمال کریں۔ Loki اور Alloy، Go programs ہیں اور ابتدا میں کوئی heap reserve نہیں کرتے، جبکہ Grafana کے مطابق monolithic Loki تقریباً 20GB فی دن تک handle کر سکتا ہے۔ OpenSearch کی sample compose configuration demo کے لیے 512 MB heap اور production example میں 2 GB heap مقرر کرتی ہے۔ Elastic کے مطابق heap کل memory کے 50% یا اس سے کم رہنا چاہیے، اس لیے 2 GB heap کا مطلب Kibana شامل کرنے سے پہلے 4 GB machine ہے۔ Logstash کی documentation خود اس کے لیے کم از کم 4GB heap تجویز کرتی ہے۔ یہ documented settings ہیں، benchmarks نہیں؛ اس لیے plan کا سائز مقرر کرنے سے پہلے اپنے load کی پیمائش کریں۔
logs کے لیے Loki اور OpenSearch میں اصل فرق کیا ہے؟
Index model۔ Loki صرف labels کو index کرتا ہے اور log body کو compressed chunks کی صورت میں محفوظ رکھتا ہے، جنہیں query کے وقت scan کیا جاتا ہے۔ اس لیے writes کم لاگت ہوتی ہیں، لیکن broad queries زیادہ مہنگی ہوتی ہیں۔ OpenSearch fields کے content کو index کرتا ہے، اس لیے arbitrary full text search تیز ہوتی ہے، جبکہ index کے لیے memory اور disk دونوں درکار ہوتے ہیں۔ Loki اس وقت منتخب کریں جب آپ کو معلوم ہو کہ کون سی service اور کون سا time window درکار ہے۔ OpenSearch اس وقت منتخب کریں جب آپ کو ایسا text search کرنا ہو جس کی پہلے سے پیش گوئی نہ کی جا سکے۔
VPS پر logs کتنے عرصے تک رکھنے چاہییں؟
Disk خود مدت مقرر کرے، اس سے پہلے آپ یہ تعداد طے کریں۔ ہر system میں اسے صرف ایک جگہ مقرر کریں: journald کے لیے MaxRetentionSec= اور SystemMaxUse=، Loki کے لیے compactor فعال ہونے کی صورت میں retention_period، اور OpenSearch کے لیے min_index_age کے ساتھ ISM policy۔ زیادہ تر single server setups میں 14 سے 30 دن debugging اور incident review کے لیے کافی ہوتے ہیں۔ جو data زیادہ عرصے تک رکھنا ضروری ہو، اسے server سے باہر محفوظ کی گئی copy میں رکھیں، کیونکہ ناکام ہونے والے server پر صرف محفوظ log کوئی قابل اعتماد record نہیں ہوتا۔
کیا logs کو Loki تک پہنچانے کے لیے اب بھی Promtail استعمال کرنا چاہیے؟
نہیں۔ Promtail 2 March 2026 کو end of life ہو گیا، اور Grafana Alloy اس کی جگہ لے چکا ہے۔ Loki کی اپنی Docker installation example اب Alloy configuration فراہم کرتی ہے، اور Grafana ایک converter فراہم کرتا ہے جو موجودہ Promtail config کو Alloy syntax میں تبدیل کر دیتا ہے۔ موجودہ Promtail installation چلتی رہے گی، لیکن اسے مزید fixes نہیں ملیں گے۔ اس لیے migration کو maintenance سمجھیں، نہ کہ ایسی upgrade جسے غیر معینہ مدت تک مؤخر کیا جا سکے۔