স্বাগতম! আজকে আমরা Serilog-এর অন্যতম পাওয়ারফুল এবং অ্যাডভান্সড একটি ফিচার শিখতে যাচ্ছি—Serilog IDiagnosticContext।
আপনার Outline অনুযায়ী, আমরা এখন Section 20: Logging-এর চতুর্দশ লেকচার “279. Serilog IDiagnosticContext”-এ আছি। আগের লেকচারে আমরা স্ট্যাটিক ডেটা (যেমন: ApplicationName) লগে যুক্ত করা শিখেছিলাম। কিন্তু আপনি যদি চান আপনার কোডের যেকোনো জায়গা (যেমন: Service Layer) থেকে রানটাইমে তৈরি হওয়া ডায়নামিক ডেটা (যেমন: ডেটাবেস থেকে আসা ইউজার লিস্ট) লগে সেভ করবেন, তবে আপনাকে IDiagnosticContext ব্যবহার করতে হবে।
চলুন শুরু করা যাক!
📝 Short Summary for Quick Revision
- Difference from Log Context: Log Context-এর ডেটা ওই রিকোয়েস্টের সবগুলো লগে প্রিন্ট হয়। কিন্তু Diagnostic Context-এর ডেটা শুধুমাত্র রিকোয়েস্টের একদম শেষে তৈরি হওয়া একটি সিগেল (Single) কমপ্লিশন লগে (Endpoint Completion Log) প্রিন্ট হয়।
- Dynamic Values: এর মাধ্যমে আপনি কোডের যেকোনো লেয়ার থেকে ডায়নামিক ভ্যালু (যেমন: Database Records, Objects, Arrays) লগে যুক্ত করতে পারেন।
- Required Package: Service বা অন্য লেয়ারে এটি অ্যাক্সেস করার জন্য
Serilog.Extensions.Hostingপ্যাকেজটি ইন্সটল করতে হয়। - Implementation:
IDiagnosticContext-কে DI-এর মাধ্যমে ইনজেক্ট করে_diagnosticContext.Set("Key", Value)কল করতে হয়। - Endpoint Completion Log: এটি চালু করার জন্য
Program.csফাইলেapp.UseSerilogRequestLogging();যুক্ত করতে হয়। - ToString() Override: অবজেক্টের আসল ডেটা লগে দেখার জন্য ডোমেইন ক্লাসে (যেমন:
Person)ToString()মেথডটি ওভাররাইড করতে হয়।
🧠 Comprehensive Breakdown
এখানে আমরা লেকচারের প্রতিটি বিষয় বিস্তারিতভাবে আলোচনা করব এবং সাথে Code Implementation দেখব।
১. IDiagnosticContext কেন প্রয়োজন? (Priority: 10/10)
ধরুন, আপনার PersonsService-এর একটি মেথড ডেটাবেস থেকে ১০ জন ইউজারের লিস্ট আনছে। আপনি চাচ্ছেন এই ইউজারের লিস্টটি লগে সেভ করতে, যাতে পরে ডিবাগ করা যায় যে ঠিক কী ডেটা ডেটাবেস থেকে এসেছিল।
যদি আপনি সাধারণ Log Context ব্যবহার করেন, তবে এই বিশাল ডেটা রিকোয়েস্টের প্রতিটি লগে বারবার সেভ হবে, যা প্রচুর জায়গা নষ্ট করবে। কিন্তু IDiagnosticContext ব্যবহার করলে, আপনি রিকোয়েস্ট চলাকালীন যেকোনো জায়গা থেকে ডেটা সেট করতে পারবেন, আর Serilog সেই ডেটাগুলো জমিয়ে রেখে রিকোয়েস্ট শেষ হওয়ার পর মাত্র একবার (Completion Log-এ) রাইট করবে। এটি অত্যন্ত মেমরি-এফিশিয়েন্ট!
২. NuGet Package Installation (Priority: 9/10)
যেহেতু আমরা Controller-এর বাইরে (Service প্রজেক্টে) এটি ব্যবহার করতে চাই, তাই আমাদের Service প্রজেক্টে একটি প্যাকেজ লাগবে।
Visual Studio-এর Solution Explorer থেকে আপনার Services Project-এ রাইট ক্লিক করে Manage NuGet Packages-এ যান এবং Serilog.Extensions.Hosting ইন্সটল করুন।
(VS Code ব্যবহারকারীদের জন্য Command:)
dotnet add package Serilog.Extensions.Hosting
৩. Service Layer-এ Diagnostic Context ব্যবহার করা (Priority: 10/10)
প্যাকেজ ইন্সটল করার পর, আমরা আমাদের PersonsService ক্লাসে এটি ইনজেক্ট করব।
Code Implementation (Service Layer):
using Serilog;
public class PersonsService : IPersonsService
{
private readonly IDiagnosticContext _diagnosticContext;
private readonly IPersonsRepository _personsRepository;
// Constructor Injection
public PersonsService(IDiagnosticContext diagnosticContext, IPersonsRepository personsRepository)
{
_diagnosticContext = diagnosticContext;
_personsRepository = personsRepository;
}
public List<Person> GetFilteredPersons(string searchBy, string searchString)
{
// ডেটাবেস থেকে ডেটা আনা হচ্ছে
List<Person> persons = _personsRepository.GetFilteredPersons(searchBy, searchString);
// Diagnostic Context-এ ডায়নামিক ডেটা (লিস্ট) সেট করা হচ্ছে
_diagnosticContext.Set("Persons", persons);
return persons;
}
}
এখানে আমরা "Persons" নামে একটি Key এবং ভ্যালু হিসেবে পুরো persons অবজেক্ট লিস্টটি দিয়েছি।
৪. Program.cs-এ Endpoint Completion Log চালু করা (Priority: 10/10)
Diagnostic Context-এর ডেটাগুলো প্রিন্ট করার জন্য আমাদের Serilog-কে বলতে হবে যে রিকোয়েস্ট শেষ হলে একটি স্পেশাল লগ তৈরি করো।
Code Implementation (Program.cs):
var app = builder.Build();
// এটি যুক্ত করা বাধ্যতামূলক (রিকোয়েস্ট পাইপলাইনের একদম শুরুতে, অন্যান্য মিডলওয়্যারের আগে)
app.UseSerilogRequestLogging();
// ... অন্যান্য মিডলওয়্যার
app.UseRouting();
app.MapControllers();
app.Run();
৫. ToString() Override করা (The Secret Trick) (Priority: 9/10)
আপনি যখন উপরের কোড রান করে Seq-এ গিয়ে Completion Log (যেমন: HTTP GET responded 200) চেক করবেন, তখন দেখবেন Persons অ্যারের ভেতরে ডেটার বদলে অবজেক্টের নাম (Entities.Person) দেখাচ্ছে।
কারণ, Serilog অবজেক্টকে স্ট্রিংয়ে কনভার্ট করার জন্য ডিফল্ট ToString() কল করে। তাই আমাদের Person ক্লাসে এটি ওভাররাইড করতে হবে।
Code Implementation (Domain Entity):
public class Person
{
public Guid PersonID { get; set; }
public string? PersonName { get; set; }
// অন্যান্য প্রোপার্টি...
// Serilog যাতে আসল ডেটা বুঝতে পারে, তাই ToString() ওভাররাইড করা হলো
public override string ToString()
{
return $"Person ID: {PersonID}, Person Name: {PersonName}";
}
}
এখন আবার রান করলে Seq ড্যাশবোর্ডে আপনি ইউজারের আসল আইডি এবং নাম দেখতে পাবেন!
🚀 Best Practices & .NET Modern Updates
Best Practices for Diagnostic Context:
- Don’t Log Sensitive Data: ইউজার অবজেক্ট পুরোটাই লগে দিয়ে দিলে পাসওয়ার্ড বা ইমেইলের মতো সেনসিটিভ ডেটা লগে চলে যেতে পারে। তাই পুরো অবজেক্ট না দিয়ে শুধু প্রয়োজনীয় প্রোপার্টিগুলো (যেমন: DTO বা শুধু Name/Id)
Setকরা বেস্ট প্র্যাকটিস। - Destructuring Objects:
ToString()ওভাররাইড করা ভালো, তবে Serilog-এ অবজেক্টকে JSON আকারে সুন্দরভাবে সেভ করার জন্য Destructuring অপারেটর (@) ব্যবহার করাটা ইন্ডাস্ট্রিতে বেশি পপ্যুলার (যদিও লেকচারে এটি দেখানো হয়নি)। যেমন:_diagnosticContext.Set("Persons", persons, destructureObjects: true);
Modern .NET Updates (High-Performance Request Logging):
.NET 8 এবং 10-এ app.UseSerilogRequestLogging(); অনেক বেশি অপ্টিমাইজ করা হয়েছে। আপনি চাইলে এর ভেতরে অপশন দিয়ে নির্দিষ্ট রিকোয়েস্ট (যেমন: হেলথ চেক বা স্ট্যাটিক ফাইল) লগ হওয়া থেকে বাদ দিতে পারেন, যাতে কনসোল পরিষ্কার থাকে।
.NET 10 Implementation:
app.UseSerilogRequestLogging(options =>
{
// Health Check URL-এর জন্য লগ তৈরি করবে না
options.GetLevel = (httpContext, elapsed, ex) =>
{
if (httpContext.Request.Path == "/health")
return LogLevel.None;
return LogLevel.Information;
};
});
আশা করি IDiagnosticContext-এর পুরো বিষয়টি আপনার কাছে পরিষ্কার হয়েছে! সামনের লেকচারে আমরা “Serilog Timings” দেখব, যা পারফরম্যান্স মেজার করার জন্য দারুণ একটি ফিচার।