আপনার application এখন আরামে চলছে। Engineering team-ও একটু শান্তিতে আছে। এখন আর তাদের বেশি প্যারা নিতে হচ্ছে না। এত কিছু হওয়ার পরেও একটা জিনিস বাকি রয়ে গেছে। আপনার application-এর বয়স অনেক দিন হয়ে গেল। কিন্তু আপনাকে যদি জিজ্ঞেস করা হয় গত ১ মাসে আপনার application-এর user-এর সংখ্যা কেমন ছিল, বা ৭ দিনের? এই প্রশ্নের উত্তর আপনি এখন শুধু অনুমান করে বলতে পারবেন। Exactly কোনো data নেই।
আপনি এখন microservice architecture-এ আছেন। এখন অনেকগুলো server হয়ে গেছে। একটা service-এর জন্য multiple region-এ multiple server রয়েছে। এই serverগুলো কখন কী হচ্ছে, কোন server-এর জন্য usage কেমন, তাদের uptime record কেমন, কোনো error face করছে কিনা—এগুলো কিন্তু real-time-এ দেখার কোনো ব্যবস্থা আপনার কাছে নেই।
আরেকটা situation বলি, আপনার engineering team খুব ভালো ভাবে testing করেছে + test case লিখে রেখেছে, সেগুলো test হয়েছে। CI/CD pipeline-এ হয়েছে। এ ছাড়াও একটা systematic way-তে engineering team এমন ব্যবস্থা করেছে যে, যাই হয়ে যাক application-এ কোনো error হলে server crash করবে না। কিন্তু testing environment আর production—২টা জিনিস একেবারেই আলাদা। কখন কোন সময় কী issue হবে আপনি বলতে পারবেন না। For example, এমন একটা error হলো (rare error), error যেহেতু handle হয়েছে সেহেতু server crash করবে না। আর আপনিও বুঝতে পারবেন না যে কোনো error হয়েছে। আর আপনি বুঝতে না পারলে error solve হবে না। একটা সময় এই error-ই আপনার system crash-এর কারণ হয়ে যেতে পারে। এখন প্রশ্ন হচ্ছে এটা কীভাবে prevent করবেন?
এই situation handle করার জন্য মূলত ময়দানে আসে Observability। এর মাধ্যমে আপনার application-এর যাবতীয় information real-time-েই দেখতে পারবেন।
Observability-র তিনটা Pillar
Logs
একটা জিনিস খেয়াল করবেন, বড় building + office-এর gate-এ একজন guard থাকেন যিনি building-এ কে entry নিচ্ছে আর কে building থেকে বাইরে যাচ্ছে সব কিছুর record রাখছেন। এইটা রাখার মূল কারণ হচ্ছে যদি কোনো incident হয় তাহলে এটা helpful হবে। এই entryগুলোই হচ্ছে logs।
Similar way-তে application-এ কে access করছে, কী access করছে, তাকে কী response দেওয়া হয়েছে, কোনো error হয়েছে কিনা, কী error হয়েছে—এই সবকটি জিনিস store করে রাখা হয় যাতে পরে এগুলো analysis করা যায়।
মূলত এই logs-এর মাধ্যমেই application level error + bug-এর solution করা হয়ে থাকে। অনেক ক্ষেত্রে infrastructure related errorগুলোও এই logs analysis করার মাধ্যমে বের করা যায়।
Metrics
এইটা log-এর মতোই, তবে এটা infrastructure level-এ কাজ করে। যেমন সার্ভার কতগুলো, তাদের CPU, memory usage কেমন, তারা কেমন user serve করছে, তাদের health কেমন, কোনো fault আছে কিনা—এই সব কিছু metrics-এর মাধ্যমে বের করা যায়।
Traces
একটা গল্প বলি, আপনি নিশ্চয়ই কোনো গুপ্তধন খোঁজার রহস্যের গল্প পড়েছেন অথবা movies-এ দেখেছেন। ওখানে একটা জিনিস খেয়াল করবেন যে একটা ছোট information decode করে step-by-step ওই গুপ্তধনের কাছে পৌঁছে যায়। এই যে step-by-step, একটা জিনিস থেকে অন্য একটা জিনিসে যাওয়ার history-টাই হচ্ছে traces।
অনেক সময় application-এ কোনো একটা request কোন layer (services) হয়ে গেছে তা জানার প্রয়োজন হয়। এই জন্য প্রতিটা request-এর history store করার প্রয়োজন হয়। Tracing-টা সব থেকে বেশি কাজে লাগে যখন কোনো error হয়। একটা error আসলে কোনো service-এর কোনো file-এর কারণে হয়েছে তা এই tracing-এর মাধ্যমে easily identify করা যায়।
Structured Logging
অগোছালো জিনিস নিয়ে কাজ করা একটু ঝামেলার, process করতে অনেক problem face করা লাগে + output properly generate করা possible না। এখন আপনি যদি logsগুলো অগোছালোভাবে store করেন তাহলে সেখান থেকে data output generate করা tough। এই জন্য structured way-তে log store করা দরকার। এই structured dataগুলো সব predictable, এই জন্য আপনি চাইলেই processing-এর জন্য একটা program লিখে রাখতে পারেন।
// ❌ এটা search করা কঠিন
console.log(`User 5 placed order 123 at ${new Date()}`);
// ✅ এটা search, filter, aggregate করা যায়
logger.info("Order placed", {
userId: 5,
orderId: 123,
amount: 1500,
timestamp: new Date().toISOString(),
requestId: req.headers["x-request-id"],
});
Structured log মানেই হচ্ছে JSON। JSON data-এর ওপর easily query করা যায়।
Logging-এর জন্য অনেক ধরনের tool আছে, for example: Elasticsearch, CloudWatch, Loki ইত্যাদি। এগুলো dynamically আপনার করা logsগুলো store করে সেখান থেকে process করবে। এই সব toolগুলো default ভাবেই JSON data parse করতে পারে।
Log Levels
logger.error("Payment failed", { error, userId }); // Alert দরকার
logger.warn("High memory usage", { usage: "85%" }); // নজরে রাখো
logger.info("Order created", { orderId }); // Normal flow
logger.debug("Cache miss", { key }); // Dev only
Log level-টা error বা bug resolve করার জন্য খুবই কাজে লাগে। একটা application যেখানে ১ মিলিয়ন user আছে সেখানে যদি সব log-ই সেম থাকে তাহলে আপনাকে error খুঁজতে বেগ পেতে হবে। আর logging toolগুলো কিছুই করতে পারবে না।
Suppose আপনি application-এ কী কী error encounter হয়েছে সেগুলো দেখতে চাচ্ছেন, তখন আপনি just error log level দিয়ে filter করলেই error related সবগুলো পেয়ে যাবেন। Proper way-তে log level maintain করলে log analysis করা easy হয়ে যায়।
একটা জিনিস, debug level-টা শুধুমাত্র dev environment-এর জন্য use করবেন। Production-এ যেন এই debug level-টা off করা থাকে, না হয় অনেক unnecessary log store হয়ে যাবে।
Metrics
Production-এ CPU, memory, response time, active user count — এই সংখ্যাগুলো সবসময় monitoring-এর মধ্যে রাখা হয়।
// Prometheus metrics
const httpRequestDuration = new Histogram({
name: "http_request_duration_seconds",
help: "HTTP request duration",
labelNames: ["method", "route", "status_code"],
buckets: [0.1, 0.5, 1, 2, 5],
});
Dashboard-এ দেখতে পাবেন —
- প্রতি সেকেন্ডে কতটা request আসছে
- Average response time
- Error rate
- DB connection pool usage
Distributed Tracing: Request-এর পুরো যাত্রা
এই জিনিসটা একটা Nightmare। আপনি যখন Microservices Architecture + Multiple region-এ support দেন তখন by default "API Gateway", "Load Balancer" এই জিনিসগুলো চলে আসে। Similar type-এর অনেক জিনিসপত্র এখানে use হওয়াটা নরমাল ব্যাপার। একটা request কোথায় কোথায় যাচ্ছে, কোন কোন layer দিয়ে যাচ্ছে, কত time নিচ্ছে—এই জিনিসগুলোর trace রাখাটা দরকার। System optimize করার ক্ষেত্রে এগুলো কাজে লাগে।
For example, আপনার application-এর জন্য Asia + Europe, দুই জায়গায় server আছে। কিন্তু Asia থেকে request গেলে তার latency অনেক বেশি হচ্ছে, কিন্তু Europe-এর টা ঠিকই আছে। এই ক্ষেত্রে আপনি কীভাবে বিষয়টাকে deal করবেন?
এই distributed tracing-এর মাধ্যমে আপনি জানতে পারেন, Asia থেকে যে requestগুলো যাচ্ছে সেগুলো সব America-তে থাকা server থেকে response আসছে। আরেকটু analysis করার পরে বুঝতে পারলেন যে load balancer এই কাজটা করছে। এখন আপনি কিন্তু latency বেশি হওয়ার reason-টা জানেন। এই problem solve করা আপনার জন্য খুব বেশি problem হবে না।
Standard Tool: OpenTelemetry (OTel)
Distributed Tracing implementation জন্য বর্তমান industry gold standard হলো OpenTelemetry (OTel)।
আগে ডেটা কালেক্ট করার জন্য একেক টুলের (Datadog, New Relic, Jaeger) আলাদা আলাদা লাইব্রেরি দিয়ে কোড instrument করতে হতো, যার ফলে অন্য কোনো vendor switch করা অত্যন্ত কঠিন ছিল (Vendor Lock-in)।
OpenTelemetry এই সমস্যার সমাধান করে:
- Vendor-Neutral: কোডে একবার OTel SDK দিয়ে trace/metrics/logs বসাবেন, এরপর কনফিগারেশন চেঞ্জ করে Jaeger, Prometheus বা যেকোনো cloud provider-এ পাঠাতে পারবেন; কোড পরিবর্তন করতে হবে না।
- Context Propagation: microservice-এর একটি service যখন অন্য service-কে কল করে তখন OTel automatically HTTP হেডার দিয়ে
traceparent(Trace ID এবং Span ID) পাস করে দেয়। ফলে পুরো request journey-এর প্রতিটি স্টেপ একটি একক সূত্রে গেঁথে যায়।
Alerting: ঘুম থেকে তুলবে
ছোটবেলায় যখন কোনো মিশন (আপনি জানেন কী mean করছি) করতে যেতাম, তখন ১ জনকে পাহারা দিতে বলতাম। তাকে বলা ছিল যে, যদি কেউ ধারের কাছে আসে তাহলে আমাদেরকে একটা sound দিয়ে জানিয়ে দিবি, আমরা safe zone-এ চলে যাব। আসলে ওই ১ জন ছিল আমাদের alerting system।
Application-এর ক্ষেত্রে এই alerting প্রয়োজন। এই alerting system-এর threshold set করা রাখতে হবে আর সেটা check হবে metrics-এর মাধ্যমে। Threshold cross করলেই alert দেবে।
বটম লাইন
Production system মানে অন্ধকারে কাজ না। Logs, Metrics, Traces — এই তিনটা ঠিকঠাক থাকলে যেকোনো incident দ্রুত diagnose করা যায়। Observability-তে invest করা কোনো luxury না। এটা professional software engineering-এর requirement।