ایونٹ سورسنگ اور آڈٹ لاگز میں یونکس ٹائم اسٹیمپس

ایونٹ سورسنگ اور آڈٹ لاگنگ دونوں ایک بنیادی شرط پر انحصار کرتی ہیں: ہر ایونٹ کے پاس ایک درست، قابلِ موازنہ ٹائم اسٹیمپ ہونا چاہیے جس پر ترتیب (ordering) کے لیے اعتماد کیا جا سکے۔ یونکس ٹائم اسٹیمپس اس کے لیے معیاری ٹول ہیں — مگر ان میں اتنے “ایج کیسز” موجود ہیں کہ غلطی کی صورت میں حقیقی مسائل پیدا ہو جاتے ہیں۔

اپنے لاگز میں موجود کسی بھی ٹائم اسٹیمپ کو پڑھنے کے قابل تاریخ میں بدلنے یا اسے ویریفائی کرنے کے لیے Unix Timestamp Converter استعمال کریں۔ یہ مضمون خاص طور پر ایونٹ سورسنگ اور آڈٹ لاگ سسٹمز سے متعلق پیٹرنز اور pitfalls پر فوکس کرتا ہے۔

یونکس ٹائم اسٹیمپس ایونٹ سسٹمز کے لیے کیوں موزوں ہیں

ایونٹ اسٹور یا آڈٹ لاگ بنیادی طور پر “حقائق” کی ایک ترتیب ہے: "یوزر X نے وقت T پر Y کیا۔" ٹائم اسٹیمپ T کو یہ ہونا چاہیے:

  • غیر مبہم: نہ ٹائم زون کی تشریح، نہ لوکیل کے مطابق فارمیٹنگ
  • قابلِ موازنہ: ایونٹس کو ترتیب دے کر پوچھ سکیں کہ "پہلے کیا ہوا؟"
  • کمپیکٹ: 10 ہندسوں کا انٹیجر اسٹور کرنا مکمل datetime سٹرنگ کے مقابلے میں سستا ہے
  • حساب کتاب کے لیے آسان: "گزشتہ 24 گھنٹوں کے تمام ایونٹس" = WHERE ts > (now - 86400)، نہ کہ سٹرنگ پارسنگ

یونکس ٹائم اسٹیمپس ان چاروں کو پورا کرتے ہیں۔ یہ 1 جنوری 1970 UTC سے لے کر اب تک کے سیکنڈز (یا ملی سیکنڈز) کی تعداد ہیں — ایک ایسا واحد انٹیجر جسے ہر سسٹم compare، sort اور compute کر سکتا ہے۔

اس کے برعکس، فارمیٹڈ سٹرنگز کے طور پر ٹائم اسٹیمپس اسٹور کرنے سے پارسنگ اوورہیڈ، ٹائم زون کی ابہام، اور لوکیل کے لحاظ سے مختلف رویّے پیدا ہوتے ہیں۔ 2026-04-08T14:30:00+02:00 جیسی ISO 8601 سٹرنگ کو compare کرنے سے پہلے parse کرنا پڑتا ہے؛ جبکہ یونکس ٹائم اسٹیمپ کو نہیں۔

سیکنڈز بمقابلہ ملی سیکنڈز: ایک منتخب کریں اور مستقل رہیں

ایونٹ سسٹمز میں یونکس ٹائم اسٹیمپ کا سب سے عام بگ سیکنڈز اور ملی سیکنڈز کو مکس کرنا ہے۔ Python کا time.time() سیکنڈز دیتا ہے۔ JavaScript کا Date.now() ملی سیکنڈز دیتا ہے۔ PostgreSQL کا EXTRACT(EPOCH FROM NOW()) فریکشنل پریسیژن کے ساتھ سیکنڈز دیتا ہے۔ MySQL کا UNIX_TIMESTAMP() سیکنڈز دیتا ہے۔

اگر آپ کا ایونٹ پروڈیوسر Node.js سروس ہے اور کنزیومر Python سروس، اور دونوں واضح طور پر convert نہیں کرتے، تو ٹائم اسٹیمپس 1,000 کے فیکٹر سے غلط ہو سکتے ہیں۔ ملی سیکنڈ ٹائم اسٹیمپ اگر سیکنڈز سمجھ کر اسٹور ہو جائے تو ایونٹ 2001 میں ہوا ہوا لگے گا۔ سیکنڈز اگر ملی سیکنڈز سمجھ لیے جائیں تو ایونٹ 1970 کا دکھائی دے گا۔

عملی اصول: آرکیٹیکچر کی سطح پر فیصلہ کریں کہ آپ کا ایونٹ سسٹم سیکنڈز استعمال کرتا ہے یا ملی سیکنڈز، اسے واضح طور پر document کریں، اور ہر پروڈیوسر پر enforce کریں۔ ایک helper لکھنا — toUnixSeconds() یا toUnixMs() — جو ایک بار standardize کر دے اور ہر جگہ استعمال ہو، اکثر worth ہوتا ہے۔

زیادہ تر آڈٹ لاگز اور ایونٹ سورسنگ کے لیے ملی سیکنڈز بہتر انتخاب ہیں۔ ایک ہی سیکنڈ کے اندر متعدد ایونٹس عام ہیں (متعدد کلکس، متعدد state transitions)، اور ملی سیکنڈ پریسیژن آپ کو انہیں صحیح ترتیب میں رکھنے کے لیے کافی ریزولوشن دیتی ہے، نینو سیکنڈ کی پیچیدگی کے بغیر۔

ایونٹ آرڈرنگ: جب ٹائم اسٹیمپس کافی نہیں ہوتے

یونکس ٹائم اسٹیمپس آپ کو بتاتے ہیں کہ ایونٹ پروڈیوس کرنے والے سسٹم نے اسے کب ریکارڈ کیا۔ ڈسٹری بیوٹڈ سسٹم میں یہ مسئلہ بن جاتا ہے: دو مختلف سرورز پر “ایک ہی وقت” کے آس پاس ہونے والے ایونٹس میں چند ملی سیکنڈ کا فرق ہو سکتا ہے — اس لیے نہیں کہ واقعات مختلف وقت پر ہوئے، بلکہ اس لیے کہ سرور کلاک تھوڑی سی out of sync ہوتی ہیں۔

یہی ڈسٹری بیوٹڈ ایونٹ سسٹمز میں صرف wall-clock timestamps کو ordering میکانزم بنانے کا بنیادی مسئلہ ہے۔

Clock skew — دو سرورز کی گھڑیوں کے درمیان فرق — ملی سیکنڈز سے لے کر سیکنڈز تک ہو سکتا ہے، خاص طور پر اگر سخت NTP synchronization نہ ہو۔ اگر کنزیومر ایونٹس کو ٹائم اسٹیمپ کی بنیاد پر ترتیب دے، اور ایونٹس کئی پروڈیوسرز سے آ رہے ہوں، تو skew کی وجہ سے ترتیب غلط ہو سکتی ہے۔

Clock drift مزید خراب ہے: اگر ایک سرور کی گھڑی معمولی تیز یا سست چل رہی ہو تو وقت کے ساتھ وہ حقیقی وقت سے دور ہوتی جاتی ہے۔ NTP sync اسے وقتاً فوقتاً درست کرتا ہے، مگر یہ correction خود اچانک ٹائم اسٹیمپ کو آگے یا پیچھے چھلانگ دلا سکتا ہے، جس سے کچھ دیر کے لیے ایونٹ ٹائم اسٹیمپس non-monotonic ہو سکتے ہیں۔

Leap seconds کبھی کبھار UTC میں 1 سیکنڈ کا اضافہ ہوتے ہیں تاکہ زمین کی گردش کے فرق کی تلافی ہو سکے۔ یونکس ٹائم اسٹیمپس leap seconds کو represent نہیں کرتے — یونکس ٹائم اسکیل بس آخری سیکنڈ کو دہرادیتا ہے، یعنی یونکس ٹائم میں کچھ سیکنڈز wall-clock میں 2 سیکنڈ لمبے ہوتے ہیں۔ زیادہ تر سسٹمز اسے transparently handle کرتے ہیں، مگر آڈٹ سسٹمز جو leap second boundary کے پار یونکس ٹائم اسٹیمپس compare کرتے ہیں، انہیں غیر متوقع ordering نظر آ سکتی ہے۔

قابلِ اعتماد ایونٹ آرڈرنگ کے حل

Logical clocks / vector clocks: صرف wall-clock time پر انحصار کرنے کے بجائے ایک منطقی کاؤنٹر استعمال کریں جو ہر ایونٹ کے ساتھ بڑھتا جائے۔ Lamport timestamps اور vector clocks causal ordering — "ایونٹ A، ایونٹ B سے پہلے ہوا" — کو capture کرتے ہیں، synchronized clocks کے بغیر۔

Partition کے اندر sequence numbers: Kafka اور اسی طرح کے event streaming سسٹمز ایک partition کے اندر monotonically increasing sequence numbers دیتے ہیں۔ ایک partition کے اندر یہ قابلِ اعتماد ordering میکانزم ہے۔ partitions کے درمیان اضافی لاجک چاہیے۔

Hybrid Logical Clocks (HLCs): wall-clock time اور logical counters کا امتزاج۔ ٹائم اسٹیمپ monotonic رہتا ہے، حقیقی وقت کے قریب بھی رہتا ہے، اور clock skew کی صورت میں logical component بڑھا کر اسے handle کرتا ہے جب کوئی موصولہ ٹائم اسٹیمپ مقامی کلاک سے آگے ہو۔

زیادہ تر آڈٹ لاگ سسٹمز میں، جہاں ڈسٹری بیوٹڈ نوڈز کے پار سخت causal ordering ضروری نہیں، ایک ملی سیکنڈ یونکس ٹائم اسٹیمپ کے ساتھ server identifier ریکارڈ کرنا کافی ہے۔ سرور ID ایک جیسے ٹائم اسٹیمپس والے ایونٹس کو الگ کرتا ہے، اور ٹائم اسٹیمپ عملی آڈٹ مقاصد کے لیے حقیقی وقت کے کافی قریب رہتا ہے۔

ایونٹ اسٹورز میں ٹائم اسٹیمپس اسٹور کرنا

Integer column type: ریلیشنل ڈیٹابیس میں یونکس ٹائم اسٹیمپس کو BIGINT (8-byte integer) میں اسٹور کریں۔ INT (4-byte) ملی سیکنڈ ٹائم اسٹیمپس کے لیے ناکافی ہے اور 2038 سے پہلے overflow ہو جائے گا، حتیٰ کہ سیکنڈ پریسیژن کے لیے بھی۔ BIGINT ملی سیکنڈ ٹائم اسٹیمپس کو سال 292,471,208 تک handle کرتا ہے۔

Indexing: ایونٹ ٹیبلز میں ٹائم اسٹیمپ کالم تقریباً ہمیشہ index ہونا چاہیے۔ عام queries — "وقت T کے بعد کے ایونٹس"، "T1 سے T2 کے درمیان"، "تازہ ترین N ایونٹس" — سب کو timestamp کالم پر B-tree index سے فائدہ ہوتا ہے۔

Partitioning: high-volume ایونٹ ٹیبلز کو وقت کے حساب سے partition کرنا مفید ہوتا ہے (ماہ یا ہفتہ کے حساب سے)۔ اس سے index سائز manageable رہتے ہیں اور پرانے partitions کو archive یا delete کرنا آسان ہو جاتا ہے، بغیر مین ٹیبل اسٹرکچر متاثر کیے۔

Immutability: ایونٹ اسٹور میں ایونٹس immutable ہونے چاہئیں — ایک بار لکھنے کے بعد ٹائم اسٹیمپ کو کبھی update نہ کریں۔ اگر کبھی ٹائم اسٹیمپ درست کرنا پڑے (جو کہ نایاب ہونا چاہیے)، تو اصل ایونٹ بدلنے کے بجائے ایک compensating event لکھیں۔

آڈٹ لاگ ٹائم اسٹیمپس: کیا کیا کیپچر کریں

ایک اچھا آڈٹ لاگ انٹری کم از کم یہ کیپچر کرے:

  • event_time: یونکس ٹائم اسٹیمپ (ملی سیکنڈز) جب ایونٹ ہوا
  • recorded_time: یونکس ٹائم اسٹیمپ جب ایونٹ لاگ میں لکھا گیا (اگر batching یا delay ہو تو event_time سے مختلف ہو سکتا ہے)
  • actor_id: کس نے کارروائی کی
  • action: کیا کیا گیا
  • resource_id: کس چیز پر اثر پڑا
  • source_ip یا session_id: کارروائی کہاں سے آئی (سیکیورٹی آڈٹ ٹریل کے لیے)

event_time اور recorded_time کا فرق buffering، batching یا async processing والے سسٹمز میں اہم ہے۔ اگر ایونٹ 500ms بعد ریکارڈ ہو، تو یہ گیپ دوسرے سسٹم لاگز کے ساتھ correlate کرتے وقت معنی رکھتا ہے۔

دونوں ٹائم اسٹیمپس کو یونکس ملی سیکنڈ انٹیجرز کے طور پر اسٹور کریں۔ جب یوزرز کو دکھائیں تو یوزر کے لوکل ٹائم زون میں convert کریں — مگر اسٹور اور query UTC انٹیجرز میں کریں۔

انسانی ریویو کے لیے آڈٹ ٹائم اسٹیمپس کنورٹ کرنا

آڈٹ لاگز میں خام یونکس ٹائم اسٹیمپس انسان کے لیے پڑھنے کے قابل نہیں ہوتے۔ لاگز کا ریویو کرتے وقت — incident investigation، compliance audit، یا security review میں — آپ کو متعلقہ سیاق کے لیے ٹائم اسٹیمپس کو لوکل ٹائم میں convert کرنا ہوتا ہے۔

Unix Timestamp Converter انفرادی ٹائم اسٹیمپس کے لیے اسے تیز بناتا ہے۔ بڑے پیمانے پر لاگ اینالسس کے لیے، زیادہ تر لاگ مینجمنٹ ٹولز (Splunk, Datadog, Elastic) اپنی query interfaces میں خود ہی یونکس ٹائم اسٹیمپس کو انسانی پڑھنے کے قابل فارمیٹ میں بدل دیتے ہیں۔

ایک عملی نوٹ: incident reports یا audit findings میں جب آپ کنورٹڈ ٹائم اسٹیمپس لکھیں تو ہمیشہ یہ ریکارڈ کریں کہ کس ٹائم زون میں ہیں۔ "ایونٹ 14:32:07 پر ہوا" مبہم ہے؛ "14:32:07 UTC (Unix timestamp 1744123927)" غیر مبہم، قابلِ تکرار ہے۔

ٹائم اسٹیمپ ہیوی ایونٹ سسٹمز میں عام بگز

ٹائم اسٹیمپس کو سٹرنگز کے طور پر اسٹور کرنا: VARCHAR میں ٹائم اسٹیمپس نہ تو مؤثر طریقے سے index ہوتے ہیں نہ ہی range queries کے لیے اچھے ہیں۔ اس سے پروڈیوسرز کے درمیان فارمیٹ میں عدم یکسانیت بھی بڑھتی ہے۔

UTC کے بجائے لوکل ٹائم استعمال کرنا: اگر کوئی پروڈیوسر UTC کے بجائے localtime() ریکارڈ کرے تو ٹائم اسٹیمپس ٹائم زون پر منحصر ہو جائیں گے۔ daylight saving کی تبدیلیوں کے دوران ambiguous یا duplicate ٹائم اسٹیمپس ملیں گے (fall-back میں "02:30:00" پر دو مختلف ایونٹس)۔

جب ایونٹس burst میں ہوں تو سیکنڈ پریسیژن پر truncate کرنا: اگر 50 ایونٹس ایک ہی سیکنڈ میں ہوں اور سب کا ٹائم اسٹیمپ ایک ہو، تو اس سیکنڈ کے اندر ordering ختم ہو جاتی ہے۔ جہاں sub-second ordering اہم ہو وہاں ملی سیکنڈ پریسیژن استعمال کریں۔

ایونٹ پروسیسنگ ڈیلی کو نظرانداز کرنا: ایک میسج T=1000 پر queued، T=1500 پر dequeued اور T=2000 پر processed ہو تو تین مختلف ٹائم اسٹیمپس ہیں۔ آپ کون سا ریکارڈ کرتے ہیں، اسی سے آڈٹ لاگ کا “کب ہوا” متعین ہوتا ہے۔ زیادہ تر مقاصد کے لیے، جب ایونٹ واقعی ہوا (T=1000) اسے ریکارڈ کریں، نہ کہ جب processed ہوا۔

کلائنٹ کے بھیجے گئے ٹائم اسٹیمپس بغیر ویلیڈیشن قبول کرنا: اگر کوئی کلائنٹ اپنے request payload میں event_time بھیجتا ہے تو ویلیڈیٹ کریں کہ یہ سرور کے موجودہ وقت کے معقول ونڈو میں ہے (مثلاً ±5 منٹ)۔ بغیر ویلیڈیشن arbitrary timestamps قبول کرنے سے ایونٹس backdate یا antedate ہو سکتے ہیں، جو آڈٹ integrity کو توڑ دیتا ہے۔

متعلقہ مضامین