১০ নভে, ২০২৫·6 মিনিট পড়তে

Go OpenTelemetry ট্রেসিং: end-to-end API দৃশ্যমানতা

প্রায়োগিক ধাপে Go OpenTelemetry ট্রেসিং ব্যাখ্যা — কীভাবে HTTP রিকোয়েস্ট, ব্যাকগ্রাউন্ড জব এবং থার্ড-পার্টি কল জুড়ে ট্রেস, মেট্রিক্স ও লগ কোরিলেট করবেন।

Go OpenTelemetry ট্রেসিং: end-to-end API দৃশ্যমানতা

Go API-এ end-to-end ট্রেসিং কী বোঝায়

একটি ট্রেস হলো একটি অনুরোধ যখন আপনার সিস্টেমের মধ্য দিয়ে যায় তখন তার টাইমলাইন। এটি তখন শুরু হয় যখন একটি API কল আসে এবং তখন শেষ হয় যখন আপনি রেসপন্স পাঠান।

একটি ট্রেসের ভেতরে স্প্যান থাকে। একটি স্প্যান হলো একটি নির্দিষ্ট টাইমকৃত ধাপ, যেমন “অনুরোধ পার্স করা,” “SQL চালানো,” বা “পেমেন্ট প্রোভাইডারকে কল করা।” স্প্যানগুলো দরকারী ডিটেইলও বহন করতে পারে, যেমন একটি HTTP স্ট্যাটাস কোড, নিরাপদ ইউজার আইডেন্টিফায়ার, বা একটি কুয়েরি কত সারি রিটার্ন করেছে।

“End-to-end” মানে ট্রেস আপনার প্রথম হ্যান্ডলারে থেমে না। এটি এমন জায়গাগুলোতে অনুরোধটি অনুসরণ করে যেখানে সাধারণত সমস্যা লুকায়: মিডলওয়্যার, ডাটাবেস কুয়েরি, ক্যাশ কল, ব্যাকগ্রাউন্ড জব, থার্ড-পার্টি API (পেমেন্ট, ইমেইল, ম্যাপ), এবং অন্যান্য অভ্যন্তরীণ সার্ভিস।

ট্রেসিং সবচেয়ে মূল্যবান যখন সমস্যা ইন্টারমিটেন্ট হয়। যদি 200 অনুরোধের মধ্যে একটা ধীরে চলে, লগগুলো দ্রুত ও ধীর কেসে একরকম দেখায়। একটি ট্রেস সেই পার্থক্যটি স্পষ্ট করে: একটা অনুরোধ 800 ms ব্যয় করেছে একটি এক্সটার্নাল কলের অপেক্ষায়, দু'বার রিট্রাই করেছে, তারপর একটি ফলো-আপ জব চালিয়েছে।

লগগুলোও সার্ভিসগুলোর মাঝে যুক্ত করা কঠিন। আপনার কাছে API-তে একটি লগ লাইন থাকতে পারে, ওয়ার্কার-এ আরেকটি এবং এর মাঝখানে কিছুই না। ট্রেসিংয়ের সাথে, সেই ইভেন্টগুলো একই trace ID ভাগ করে, তাই অনুমান না করে আপনি চেইনটি অনুসরণ করতে পারেন।

ট্রেস, মেট্রিক্স, ও লগ: কীভাবে এগুলো একসাথে মিলে

ট্রেস, মেট্রিক্স, এবং লগ ভিন্ন প্রশ্নের উত্তর দেয়।

ট্রেস দেখায় এক রিয়েল অনুরোধে কী হয়েছে। তা বলে কত সময় কেবে গেছে আপনার হ্যান্ডলার, ডাটাবেস কল, ক্যাশ লুকআপ এবং থার্ড-পার্টি রিকোয়েস্টগুলোর মধ্যে।

মেট্রিক্স ট্রেন্ড দেখায়। সতর্কবার্তা সেট করতে এদেরই সবচেয়ে ভালো কারণ এগুলো স্থিতিশীল এবং অ্যাগ্রিগেট করা সস্তা: লেটেন্সি পার্সেন্টাইল, রিকোয়েস্ট রেট, এরর রেট, কিউ ডেপথ, এবং স্যাচুরেশন।

লগগুলো হলো প্লেইন টেক্সটে “কেন”: ভ্যালিডেশন ফেইলিওর, অপ্রত্যাশিত ইনপুট, এজ কেস, এবং আপনার কোড যে সিদ্ধান্ত নিয়েছে তার কারণ।

বাস্তব সুবিধা হলো করিলেশন। যখন একই trace ID স্প্যান এবং স্ট্রাকচারড লগে দেখা যায়, আপনি একটি এরর লগ থেকে সোজা নির্দিষ্ট ট্রেসে কুড়িয়ে যেতে পারেন এবং তৎক্ষণাৎ দেখতে পারেন কোন ডিপেন্ডেন্সি ধীর ছিল বা কোন ধাপ ব্যর্থ হয়েছে।

একটি সহজ মানসিক মডেল

প্রতিটি সিগনালকে তার সবচেয়ে উপযোগী কাজে ব্যবহার করুন:

  • মেট্রিক্স বলে কিছুর ভুল আছে।
  • ট্রেস এক অনুরোধে সময় কোথায় গেল তা দেখায়।
  • লগগুলি ব্যাখ্যা করে আপনার কোড কি সিদ্ধান্ত নিয়েছে এবং কেন।

উদাহরণ: আপনার POST /checkout এন্ডপয়েন্ট টাইমআউট হতে শুরু করে। মেট্রিক্স দেখায় p95 লেটেন্সি বেড়েছে। একটি ট্রেস দেখায় বেশি সময় পেমেন্ট প্রোভাইডার কলের মধ্যে কেটে গেছে। সেই স্প্যানের ভিতরে করেলেটেড একটি লগ লাইন দেখায় 502-কারণে রিট্রাই হচ্ছে, যা ব্যাকঅফ সেটিংস বা আপস্ট্রীম ইনসিডেন্টের দিকে ইঙ্গিত করে।

কোড যোগ করার আগে: নামকরণ, স্যাম্পলিং, এবং কি ট্র্যাক করবেন

কিছুটা পরিকল্পনা আগে থেকে করলে ট্রেস পরে সার্চযোগ্য হয়। না হলে, আপনি ডেটা সংগ্রহ করেই থাকবেন, কিন্তু মৌলিক প্রশ্নগুলো কঠিন হয়ে যাবে: “এটা staging নাকি prod ছিল?” “কোন সার্ভিস সমস্যা শুরু করেছে?”

প্রথমে ধারাবাহিক পরিচয় দিয়ে শুরু করুন। প্রতিটি Go API-র জন্য একটি পরিষ্কার service.name বেছে নিন (উদাহরণ: checkout-api) এবং একটি একক environment ফিল্ড যেমন deployment.environment=dev|staging|prod ব্যবহার করুন। এগুলো স্থিতিশীল রাখুন। যদি নাম সপ্তাহের মাঝেই বদলে যায়, চার্ট এবং সার্চগুলো ভিন্ন সিস্টেমের মতো দেখাবে।

পরবর্তীতে, স্যাম্পলিং ঠিক করুন। ডেভেলপমেন্টে প্রতিটি রিকোয়েস্ট ট্রেস করা ভালো, কিন্তু প্রোডাকশনে প্রায়শই затрат বেশি হয়। সাধারণ পদ্ধতি হলো নর্মাল ট্র্যাফিকের ছোট একটি শতাংশ স্যাম্পল করা এবং এরর ও ধীর রিকোয়েস্টগুলো সবসময় রাখা। যদি আপনি জানেন কিছু এন্ডপয়েন্ট হাই-ভলিউম (হেলথ চেক, পোলিং), সেগুলো কম ট্রেস করুন বা না ট্রেস করা বুদ্ধিমানের।

অবশেষে, ঠিক করুন কোন অ্যাট্রিবিউট স্প্যানে ট্যাগ করবেন এবং কোনগুলো কখনো সংগ্রহ করবেন না। এমন একটি সংক্ষিপ্ত allowlist রাখুন যা সার্ভিসগুলোর মাঝে ইভেন্টগুলোকে যুক্ত করতে সাহায্য করে, এবং সহজ প্রাইভেসি নীতি লিখুন।

ভাল ট্যাগগুলোর মধ্যে সাধারণত স্থিতিশীল আইডি এবং মোটা অনুরোধ তথ্য থাকে (রুট টেমপ্লেট, মেথড, স্ট্যাটাস কোড)। সংবেদনশীল পে-লোড সম্পূর্ণভাবে এড়িয়ে চলুন: পাসওয়ার্ড, পেমেন্ট ডেটা, পূর্ণ ইমেইল, অথ টোকেন, এবং কাঁচা রিকোয়েস্ট বডি। যদি ইউজার-সংক্রান্ত মান অবশ্যই যোগ করতে হয়, তবে সেগুলো হ্যাশ বা রিড্যাক্ট করে যোগ করুন।

ধাপে ধাপে: একটি Go HTTP API-তে OpenTelemetry ট্রেসিং যোগ করা

আপনি স্টার্টআপে একবার একটি tracer provider সেট করবেন। এটি নির্ধারণ করে স্প্যানগুলো কোথায় যাবে এবং কোন resource অ্যাট্রিবিউট প্রতিটি স্প্যানে যুক্ত থাকবে।

1) OpenTelemetry ইনিশিয়ালাইজ করুন

service.name সেট করা নিশ্চিত করুন। এটি না থাকলে বিভিন্ন সার্ভিসের ট্রেসগুলো মিশে যাবে এবং চার্ট পড়তে কঠিন হবে।

// main.go (startup)
exp, _ := stdouttrace.New(stdouttrace.WithPrettyPrint())

res, _ := resource.New(context.Background(),
	resource.WithAttributes(
		semconv.ServiceName("checkout-api"),
	),
)

tp := sdktrace.NewTracerProvider(
	 sdktrace.WithBatcher(exp),
	 sdktrace.WithResource(res),
)

otel.SetTracerProvider(tp)

এটাই Go OpenTelemetry ট্রেসিংয়ের ভিত্তি। পরবর্তীতে, প্রতিটি ইনকামিং রিকোয়েস্টে একটি স্প্যান দরকার।

2) HTTP মিডলওয়্যার যোগ করুন এবং মূল ফিল্ড ক্যাপচার করুন

একটি HTTP মিডলওয়্যার ব্যবহার করুন যা স্বয়ংক্রিয়ভাবে একটি স্প্যান শুরু করে এবং স্ট্যাটাস কোড ও সময়কাল রেকর্ড করে। স্প্যানের নাম রুট টেমপ্লেট (যেমন /users/:id) দিয়ে সেট করুন, কাঁচা URL দিয়ে নয়, নইলে অসংখ্য ইউনিক পাথ হয়ে যাবে।

একটি পরিষ্কার বেসলাইন লক্ষ্য করুন: প্রতি রিকোয়েস্টে একটি সার্ভার স্প্যান, রুট-ভিত্তিক স্প্যান নাম, HTTP স্ট্যাটাস ক্যাপচার, হ্যান্ডলার ব্যর্থতা স্প্যান এয়ারর হিসেবে প্রতিফলিত করা, এবং আপনার ট্রেস ভিউয়ারে সময়কাল দৃশ্যমান।

3) ব্যর্থতাগুলো স্পষ্ট করুন

কিছুমু যায় না ঠিকমতো হলে, একটি এরর রিটার্ন করুন এবং বর্তমান স্প্যানকে failed হিসেবে মার্ক করুন। এতে করে ট্রেসটি লুকিয়ে না থেকে স্পষ্ট হয়ে যায়।

হ্যান্ডলারে আপনি করতে পারেন:

span := trace.SpanFromContext(r.Context())
span.RecordError(err)
span.SetStatus(codes.Error, err.Error())

4) লোকালভাবে trace ID ভেরিফাই করুন

API চালান এবং একটি এন্ডপয়েন্টে হিট করুন। অনুরোধ কনটেক্সট থেকে trace ID একবার লগ করে দেখুন এটি প্রতি রিকোয়েস্টে বদলাচ্ছে কি না। যদি এটি সর্বদা খালি থাকে, আপনার মিডলওয়্যার সেই কনটেক্সট ব্যবহার করছে না যা আপনার হ্যান্ডলার পাচ্ছে।

DB ও থার্ড-পার্টি কলগুলিতে কনটেক্সট বহন করা

ট্রেসেবল Go API বানান
আপনার API বাড়লে এটিকে end-to-end ইনস্টুমেন্ট করা যাবে এমনভাবে Go ব্যাকএন্ড বানান।
AppMaster ব্যবহার করে দেখুন

End-to-end দৃশ্যমানতা তখন ভেঙ্গে যায় যখন আপনি context.Context হারান। ইনকামিং রিকোয়েস্ট কনটেক্সটটি হওয়া উচিত সেই থ্রেড যেটি আপনি প্রতিটি DB কল, HTTP কল, এবং হেল্পারে পাস করবেন। যদি আপনি এটিকে context.Background() দিয়ে প্রতিস্থাপন করেন বা নিচে পাস করতে ভুলে যান, আপনার ট্রেস আলাদা, অনরিলেটেড কাজ হয়ে যায়।

আউটগোয়িং HTTP-এর জন্য, একটি ইনস্ট্রুমেন্টেড ট্রান্সপোর্ট ব্যবহার করুন যাতে প্রতিটি Do(req) বর্তমান রিকোয়েস্টের অধীনে একটি চাইল্ড স্প্যান হয়ে যায়। আউটবাউন্ড রিকোয়েস্টে W3C ট্রেস হেডার ফরওয়ার্ড করুন যাতে ডাউনস্ট্রীম সার্ভিসগুলো একই ট্রেসে তাদের স্প্যান যোগ করতে পারে।

ডাটাবেস কলের ক্ষেত্রেও একই আচরণ দরকার। একটি ইনস্ট্রুমেন্টেড ড্রাইভার ব্যবহার করুন অথবা QueryContextExecContext এর চারপাশে স্প্যান রেখে কভার করুন। কেবল নিরাপদ ডিটেইল রেকর্ড করুন। আপনি ধীর কুয়েরিগুলো খুঁজতে চান কিন্তু ডেটা লিক করতে চান না।

কম ঝুঁকিপূর্ণ এবং ব্যবহারযোগ্য অ্যাট্রিবিউটগুলোর মধ্যে রয়েছে: একটি অপারেশন নাম (উদাহরণ: SELECT user_by_id), টেবিল বা মডেল নাম, সারি গণনা (শুধু গণনা), সময়কাল, রিট্রাই কাউন্ট, এবং একটি মোটা ত্রুটির ধরন (timeout, canceled, constraint)।

টাইমআউটগুলোও গল্পের একটি অংশ, শুধুই ব্যর্থতা নয়। DB এবং থার্ড-পার্টি কলগুলির জন্য context.WithTimeout সেট করুন, এবং ক্যান্সেলেশনগুলো বায়োল আপ করতে দিন। যখন একটি কল ক্যান্সেল হয়, স্প্যানকে এরর হিসেবে মার্ক করুন এবং একটি সংক্ষিপ্ত কারণ যোগ করুন যেমন deadline_exceeded

ব্যাকগ্রাউন্ড জব ও কিউ ট্রেসিং

DB-ফার্স্ট ব্যাকএন্ড ডিজাইন করুন
PostgreSQL-এ ডাটা ভিজুয়ালি মডেল করুন, তারপর গুরুত্বপূর্ণ কুয়েরিগুলির চারপাশে ট্রেস যোগ করুন।
অ্যাপ তৈরি করুন

ব্যাকগ্রাউন্ড কাজ হচ্ছে যেখানে ট্রেসগুলো প্রায়ই থেমে যায়। একটি HTTP রিকোয়েস্ট শেষ হয়, এরপর একটি ওয়ার্কার পরে একটি ভিন্ন মেশিনে মেসেজ উঠায় এবং কোনো শেয়ার করা কনটেক্সট নেই। আপনি কিছু না করলে, আপনি দুইটি আলাদা গল্প পাবেন: API ট্রেস এবং একটি জব ট্রেস যা যেন কোথা থেকে শুরু হয়েছে।

সঠিক সমাধান সহজ: যখন আপনি একটি জব enqueue করেন, বর্তমান ট্রেস কনটেক্সট ক্যাপচার করে জব মেটাডাটায় (পে-লোড, হেডার, বা অ্যাট্রিবিউট অনুযায়ী) সংরক্ষণ করুন। যখন ওয়ার্কার শুরু করে, সেই কনটেক্সট এক্সট্রাক্ট করুন এবং মূল রিকোয়েস্টের চাইল্ড হিসেবে একটি নতুন স্প্যান শুরু করুন।

নিরাপদভাবে কনটেক্সট প্রসারিত করুন

শুধু ট্রেস কনটেক্সট কপি করুন, ইউজার ডেটা নয়.

  • কেবল ট্রেস আইডেন্টিফায়ার এবং স্যাম্পলিং ফ্ল্যাগ ইনজেক্ট করুন (W3C traceparent স্টাইল)।
  • এটিকে বিজনেস 필্ড থেকে আলাদা রাখুন (উদাহরণ: একটি ডেডিকেটেড "otel" বা "trace" ফিল্ড)।
  • যখন পড়বেন তখন অবিশ্বাসী ইনপুট হিসেবে দেখুন (ফর্ম্যাট ভ্যালিডেট করুন, মিসিং ডেটা হ্যান্ডেল করুন)।
  • টোকেন, ইমেইল, বা রিকোয়েস্ট বডি জব মেটাডাটায় রাখবেন না।

স্প্যান যোগ করার পরামর্শ (শোরগোল না করে)

রিডেবল ট্রেসগুলো সাধারণত কয়েকটি অর্থবহ স্প্যান থাকে, নয় কয়েক ডজন ছেঁড়া স্প্যান। বাউন্ডারি এবং “ওয়েট পয়েন্ট”-এর চারপাশে স্প্যান তৈরি করুন। একটি ভালো শুরু হচ্ছে API হ্যান্ডলারে একটি enqueue স্প্যান এবং ওয়ার্কার-এ একটি job.run স্প্যান।

সামান্য কনটেক্সট যোগ করুন: চেষ্টা নম্বর, কিউ নাম, জব টাইপ, এবং পে-লোড সাইজ (কন্টেন্ট নয়)। যদি রিট্রাই ঘটে, সেগুলো আলাদা স্প্যান বা ইভেন্ট হিসেবে রেকর্ড করুন যাতে ব্যাকঅফ ডিলে দেখা যায়।

শিডিউল করা টাস্কগুলোরও একটি প্যারেন্ট থাকা উচিত। যদি ইনকামিং রিকোয়েস্ট না থাকে, প্রতিটি রানকে একটি নতুন রুট স্প্যান হিসেবে তৈরি করুন এবং এটি একটি শিডিউল নাম দিয়ে ট্যাগ করুন।

লগ ট্রেসের সাথে করিলেট করুন (এবং লগগুলো সেফ রাখুন)

ট্রেস বলে সময় কোথায় গেছে। লগ বলে কী ঘটেছে এবং কেন। সেগুলোকে সংযুক্ত করার সবচেয়ে সহজ উপায় হচ্ছে প্রতিটি লগ এন্ট্রিতে trace_id এবং span_id স্ট্রাকচারড ফিল্ড হিসেবে যোগ করা।

Go-তে, সক্রিয় স্প্যান context.Context থেকে নিন এবং প্রতি রিকোয়েস্ট (বা জব) আপনার লগারকে একবার এনরিচ করুন। তারপর প্রতিটি লগ লাইন একটি নির্দিষ্ট ট্রেসকে পয়েন্ট করবে।

span := trace.SpanFromContext(ctx)
sc := span.SpanContext()
logger := baseLogger.With(
  "trace_id", sc.TraceID().String(),
  "span_id",  sc.SpanID().String(),
)
logger.Info("charge_started", "order_id", orderID)

এটাই যথেষ্ট যাতে একটি লগ এন্ট্রি থেকে সঠিক স্প্যানে ঝাঁপিয়ে পড়া যায়। এটি কনটেক্সট মিসিং স্পষ্ট করতেও সাহায্য করে: trace_id খালি থাকবে।

PII লিক না করে লগগুলো ইউজেবল রাখুন

লগগুলো প্রায়ই ট্রেস থেকেও বেশি সময় জীবনযাপন করে এবং আরও বেশি জায়গায় যায়, তাই এখানে কঠোর হওয়া দরকার। স্থিতিশীল আইডি ও ফলাফল প্রিফার করুন: user_id, order_id, payment_provider, status, এবং error_code। যদি ইউজার ইনপুট লগ করতে হয়, আগে রিড্যাক্ট করুন এবং দৈর্ঘ্য সীমা দিন।

এরর গ্রুপিং সহজ করুন

কনসিস্টেন্ট ইভেন্ট নাম এবং এরর টাইপ ব্যবহার করুন যাতে আপনি সেগুলো গণনা ও সার্চ করতে পারেন। শব্দভাণ্ডার যদি প্রতিবার পরিবর্তিত হয়, একই ইস্যুটি অনেক ভিন্ন ইস্যু মনে হবে।

এমন মেট্রিক যোগ করুন যা আসলেই সমস্যা খুঁজে পেতে সাহায্য করে

সোর্স কোডের মালিকানা নিন
প্রোডাকশন-রেডি কোড জেনারেট করুন এবং আপনার টিম পছন্দ মতো instrument করতে পারবেন।
AppMaster চেষ্টা করুন

মেট্রিক্স আপনার ран্নিং সিস্টেম। একটি সেটআপ যেখানে Go OpenTelemetry ট্রেসিং ইতিমধ্যেই আছে, সেখানে মেট্রিক্স উত্তর দেওয়া উচিত: কত ঘনঘন, কত খারাপ, এবং কখন থেকে।

প্রায় প্রতিটি API-এর জন্য একটি ছোট সেট দিয়ে শুরু করুন: রিকোয়েস্ট কাউন্ট, এরর কাউন্ট (স্ট্যাটাস ক্লাস অনুযায়ী), লেটেন্সি পার্সেন্টাইল (p50, p95, p99), ইন-ফ্লাইট রিকোয়েস্ট, এবং DB ও প্রধান থার্ড-পার্টি কলের ডিপেন্ডেন্সি লেটেন্সি।

ট্রেসের সাথে মেট্রিকসকে সঙ্গত রাখার জন্য, একই রুট টেমপ্লেট ও নাম ব্যবহার করুন। যদি আপনার স্প্যানগুলো /users/{id} ব্যবহার করে, আপনার মেট্রিক্সগুলোকেও তাই হওয়া উচিত। তাহলে যখন একটি চার্ট বলে “/checkout-এর p95 বেড়েছে,” আপনি সরাসরি ঐ রুটে ফিল্টার করা ট্রেসগুলোতে যেতে পারবেন।

লেবেল (অ্যাট্রিবিউট) নিয়ে সতর্ক থাকুন। একটি খারাপ লেবেল খরচ বাড়িয়ে দিতে পারে এবং ড্যাশবোর্ড অকার্যকর করতে পারে। রাউট টেমপ্লেট, মেথড, স্ট্যাটাস ক্লাস, এবং সার্ভিস নাম সাধারণত নিরাপদ। ইউজার আইডি, ইমেইল, ফুল URL, এবং কাঁচা এরর মেসেজ সাধারণত নিরাপদ নয়।

কয়েকটি কাস্টম মেট্রিক যোগ করুন ব্যবসায়িকভাবে জরুরি ইভেন্টের জন্য (উদাহরণ: checkout শুরু/সম্পন্ন, পেমেন্ট ফেইলিউর রিজাল্ট কোড গ্রুপ অনুযায়ী, ব্যাকগ্রাউন্ড জব সফল বনাম রিট্রাই)। সেটটি ছোট রাখুন এবং যা ব্যবহার হয় না তা সরিয়ে ফেলুন।

টেলিমেট্রি এক্সপোর্ট করা এবং নিরাপদভাবে রোল আউট করা

এক্সপোর্টিংই OpenTelemetry-কে বাস্তবে পরিণত করে। আপনার সার্ভিসকে স্প্যান, মেট্রিক্স, এবং লগ কোথাও নির্ভরযোগ্যভাবে পাঠাতে হবে যাতে রিকোয়েস্ট ধীর না হয়।

লোকালে, সরল রাখুন। কনসোল এক্সপোর্টার (বা লোকাল কলেক্টরে OTLP) দ্রুত ট্রেস দেখতে এবং স্প্যান নাম ও অ্যাট্রিবিউট ভ্যালিডেট করতে দেয়। প্রোডাকশনে, সার্ভিসের কাছে একটি এজেন্ট বা OpenTelemetry Collector-এ OTLP পাঠানো উত্তম। এতে রিট্রাই, রাউটিং, এবং ফিল্টারিং এক জায়গায় করা যায়।

বাচিং গুরুত্বপূর্ণ। সংক্ষিপ্ত ইন্টারিভালে ব্যাচে টেলিমেট্রি পাঠান, কঠোর টাইমআউট দিন যাতে নেটওয়ার্ক স্থবির হলে আপনার অ্যাপ ব্লক না হয়। টেলিমেট্রি ক্রিটিক্যাল পাথ-এ থাকা উচিত না। যদি এক্সপোর্টার ধাক্কা খায়, এটি ডেটা ড্রপ করা উচিত পরিবর্তে মেমোরি জমা করা।

স্যাম্পলিং খরচ ভবিষ্যদ্বাণীযোগ্য রাখে। হেড-ভিত্তিক স্যাম্পলিং দিয়ে শুরু করুন (উদাহরণ: 1–10% অনুরোধ), তারপর সহজ নিয়ম যোগ করুন: সব এরর স্যাম্পল করুন, এবং একটি থ্রেশহোল্ডের ওপরে ধীর রিকোয়েস্ট সবসময় স্যাম্পল করুন। যদি আপনার হাই-ভলিউম ব্যাকগ্রাউন্ড জব থাকে, সেগুলি কম রেট এ স্যাম্পল করুন।

ধাপে ধাপে রোল আউট করুন: dev-এ 100% স্যাম্পলিং, staging-এ বাস্তবসম্মত ট্র্যাফিক ও নিম্ন স্যাম্পলিং, তারপর প্রোডাকশনে রক্ষণশীল স্যাম্পলিং এবং এক্সপোর্টার ফেইলিওরে অ্যালার্ট।

সাধারণ ভুল যা end-to-end দৃশ্যমানতা নষ্ট করে

সার্ভিস নামকরণ মানক করুন
রিয়েল Go সার্ভিস জেনারেট করুন এবং সব অ্যাপে নামকরণ ও পরিবেশ ট্যাগসমূহ সঙ্গত রাখুন।
শুরু করুন

End-to-end দৃশ্যমানতা সাধারণত সাধারণ কারণে ব্যর্থ হয়: ডেটা আছে, কিন্তু এটি সংযুক্ত নয়।

Go-তে ডিস্ট্রিবিউটেড ট্রেসিং ভেঙে ফেলার সাধারণ কারণগুলো হলো:

  • লেয়ারগুলোর মধ্যে কনটেক্সট হারানো। একটি হ্যান্ডলার স্প্যান তৈরি করে, কিন্তু DB কল, HTTP ক্লায়েন্ট, বা গোরুটিন context.Background() ব্যবহার করে রিকোয়েস্ট কনটেক্সট না পাঠালে।
  • এরর রিটার্ন করলে স্প্যান মার্ক না করা। আপনি যদি err রেকর্ড না করেন এবং স্প্যান স্ট্যাটাস সেট না করেন, ট্রেসগুলি "সব ঠিক আছে" দেখায় যদিও ব্যবহারকারীরা 500 দেখছে।
  • সবকিছু ইন্সট্রুমেন্ট করা। যদি প্রতিটি হেল্পার স্প্যান হয়ে যায়, ট্রেসগুলো শব্দে ভরে যাবে এবং খরচ বেড়ে যাবে।
  • উচ্চ-কার্ডিনালিটি অ্যাট্রিবিউট যোগ করা। আইডি সহ ফুল URL, ইমেইল, কাঁচা SQL ভ্যালু, রিকোয়েস্ট বডি, বা কাঁচা এরর স্ট্রিং কোটি ধরনের ইউনিক ভ্যালু তৈরি করতে পারে।
  • কর্মক্ষমতা গড় দেখে বিচার করা। ইনসিডেন্টগুলো পার্সেন্টাইল (p95/p99) এবং এরর রেটে দেখা যায়, না যে গড় লেটেন্সি।

একটি দ্রুত স্যানিটি চেক হলো একটি রিয়েল অনুরোধ বাছাই করে তা সীমান্ত জুড়ে অনুসরণ করা। যদি আপনি একটি ট্রেস ID ইনবাউন্ড রিকোয়েস্টে, DB কুয়েরিতে, থার্ড-পার্টি কলেই, এবং অ্যাসিঙ্ক ওয়ার্কারে দেখতে না পান, তাহলে আপনার কাছে এখনও end-to-end দৃশ্যমানতা নেই।

প্রাকটিক্যাল "ডান হয়েছে" চেকলিস্ট

ব্যাকগ্রাউন্ড জব ট্রেস করুন
একটি ওয়ার্কার তৈরি করুন এবং কনটেক্সট প্রসারিত করুন যাতে অ্যাসিঙ্ক জবগুলো রিকোয়েস্টের সাথে যুক্ত হয়।
এখনই শুরু করুন

আপনি কাছাকাছি যখন একটি ইউজার রিপোর্ট থেকে সঠিক অনুরোধে গিয়ে প্রতিটি হপে তা অনুসরণ করতে পারবেন।

  • একটি API লগ লাইন বাছুন এবং trace_id দ্বারা সঠিক ট্রেসটি খুঁজুন। নিশ্চিত করুন একই অনুরোধের গভীরতর লগগুলো (DB, HTTP ক্লায়েন্ট, ওয়ার্কার) একই ট্রেস কনটেক্সট বহন করে।
  • ট্রেস খুলুন এবং নেস্টিং ভেরিফাই করুন: উপরে একটি HTTP সার্ভার স্প্যান, এবং তার চাইল্ড স্প্যানে DB কল ও থার্ড-পার্টি API। একটি ফ্ল্যাট লিস্ট প্রায়ই বোঝায় কনটেক্সট হারানো হয়েছে।
  • একটি API রিকোয়েস্ট থেকে একটি ব্যাকগ্রাউন্ড জব ট্রিগার করুন (যেমন ইমেইল রসিদ পাঠানো) এবং নিশ্চিত করুন ওয়ার্কার স্প্যান রিকোয়েস্টের সাথে যুক্ত আছে।
  • মেট্রিক্স বেসিকগুলো চেক করুন: রিকোয়েস্ট কাউন্ট, এরর রেট, এবং লেটেন্সি পার্সেন্টাইল। নিশ্চিত করুন আপনি রুট বা অপারেশনে ফিল্টার করতে পারেন।
  • অ্যাট্রিবিউট ও লগ স্ক্যান করে নিরাপত্তা নিশ্চিত করুন: কোন পাসওয়ার্ড, টোকেন, ফুল ক্রেডিট কার্ড নম্বর, বা কাঁচা পার্সোনাল ডেটা নেই।

একটি সরল বাস্তবতা পরীক্ষা হলো পেমেন্ট প্রোভাইডার ধীরে কাজ করার সিমুলেশন করা। আপনাকে একটি ট্রেস দেখতে হবে যেখানে একটি স্পষ্টভাবে লেবেল করা এক্সটার্নাল কল স্প্যান আছে, এবং একই সাথে checkout রুটে p95 লেটেন্সির একটি মেট্রিক স্পাইক।

যদি আপনি Go ব্যাকএন্ড জেনারেট করছেন (উদাহরণ: AppMaster), তাহলে এই চেকলিস্টটিকে আপনার রিলিজ রুটিনের অংশ করা উপকারী যাতে নতুন এন্ডপয়েন্ট ও ওয়ার্কার ট্রেসেবল থাকে অ্যাপ বাড়ার সাথে। AppMaster (appmaster.io) বাস্তব Go সার্ভিস জেনারেট করে, তাই আপনি একটি স্ট্যান্ডার্ড OpenTelemetry সেটআপ নির্ধারণ করে সার্ভিস ও ব্যাকগ্রাউন্ড জব জুড়ে বহন করতে পারবেন।

উদাহরণ: সার্ভিসগুলোর মধ্যে ধীর checkout ডিবাগ করা

একজন কাস্টমার বলছে: “Checkout মাঝে মাঝে আটকে যায়।” আপনি এটি অন-ডিমান্ড পুনরুৎপাদন করতে পারছেন না — ঠিক এটাই যেখানে Go OpenTelemetry ট্রেসিং কাজ দেয়।

প্রথমে মেট্রিক্স দিয়ে সমস্যার আকৃতি বুঝুন। checkout এন্ডপয়েন্টের রিকোয়েস্ট রেট, এরর রেট, এবং p95 বা p99 লেটেন্সি দেখুন। যদি ধীরতা ছোট বিস্ফোরণে হয় এবং কেবল অনুরোধের একটি অংশে ঘটে, তা সাধারণত একটি ডিপেন্ডেন্সি, কুইং, বা রিট্রাই আচরণের দিকে ইঙ্গিত করে CPU-র পরিবর্তে।

পরবর্তী ধাপ, একই টাইম উইন্ডোর একটি ধীর ট্রেস খুলুন। এক ট্রেসই প্রায়ই যথেষ্ট। একটা স্বাস্থ্যকর checkout হতে পারে 300–600 ms এন্ড-টু-এন্ড। একটি খারাপটি হতে পারে 8–12 সেকেন্ড, যেখানে বেশিরভাগ সময় একটি একক স্প্যানে কাটে।

একটি প্রচলিত প্যাটার্ন দেখা যায়: API হ্যান্ডলার দ্রুত, DB কাজ বেশিরভাগ সময় ঠিক আছে, তারপর পেমেন্ট প্রোভাইডার স্প্যান রিট্রাই দেখায় ব্যাকঅফসহ, এবং একটি ডাউনস্ট্রীম কল লক বা কিউ-র পেছনে অপেক্ষা করছে। রেসপন্স হয়তো 200 রিটার্ন করছে, তাই কেবল এরর-ভিত্তিক অ্যালার্টগুলো কখনো ট্রিগার না করতে পারে।

করেলেটেড লগগুলো তখন আপনাকে সঠিক পথ বলে দেয় সাধারণ ভাষায়: “retrying Stripe charge: timeout,” তারপর “db tx aborted: serialization failure,” এবং পরবর্তীতে “retry checkout flow।” এটা স্পষ্ট সংকেত যে কয়েকটি ছোট সমস্যা একসাথে মিলে খারাপ ইউজার এক্সপেরিয়েন্স তৈরি করছে।

বটলনেক মিললে, ধারাবাহিকতা হলো যা সময়ের সাথে পাঠযোগ্যতা রাখে। স্প্যান নাম, অ্যাট্রিবিউট (নিরাপদ ইউজার ID হ্যাশ, অর্ডার ID, ডিপেন্ডেন্সি নাম), এবং স্যাম্পলিং নিয়ম সার্ভিস জুড়ে স্ট্যান্ডার্ড করুন যাতে সবাই একইভাবে ট্রেস পড়ে।

শুরু করা সহজ
কিছু আশ্চর্যজনকতৈরি করুন

বিনামূল্যের পরিকল্পনা সহ অ্যাপমাস্টারের সাথে পরীক্ষা করুন।
আপনি যখন প্রস্তুত হবেন তখন আপনি সঠিক সদস্যতা বেছে নিতে পারেন৷

এবার শুরু করা যাক