রুবিতে লগ কর্ম
লগিং হলো একটি অ্যাপ্লিকেশনের সার্বিক প্রধান কাজগুলোর একটি। লগ ব্যবহার হয় যখন আপনাকে দরকার হয়, উদাহরণস্বরূপ,
- আপনার অ্যাপ্লিকেশনের ভিতরে কী হচ্ছে সেটি দেখা,
- তাদের মনিটর করা, অথবা
- কিছু নির্দিষ্ট ডেটার জন্য মেট্রিক্স কালেক্ট করা।
নতুন প্রোগ্রামিং ল্যাঙ্গুয়েজ শিখতে সময়, ইনফরমেশন লগ করার জন্য সবচেয়ে স্বাভাবিক পিক হলো নেটিভ মেকানিজম। এটি সাধারণত সহজ, ডকুমেন্টেড, এবং কমিউনিটিতে ভালো ছড়িয়ে থাকা।
লগ ডেটা কোম্পানি, বিজনেস, এবং আপনি যে টাইপের অ্যাপ্লিকেশনের সাথে কাজ করছেন তার ওপর নির্ভর করে অনেক ভিন্ন হয়। তাই, আপনি এবং আপনার টিম যে লগিং সলিউশন বেছে নিচ্ছেন সেটি এর সামগ্রিক ব্যবহারকে কীভাবে প্রভাবিত করবে সেটি বুঝতে খুব গুরুত্বপূর্ণ।
এই আর্টিকেলে, আমরা রুবি এবং রেইলসে লগিং-এর উপলব্ধ অপশনগুলোয় একটা রাইড নেব, বিল্ট-ইন موارد থেকে প্রিয় থার্ড-পার্টি কমিউনিটি ফ্রেমওয়ার্ক পর্যন্ত। চলুন!
রুবির বিল্ট-ইন অপশন
রুবি লগিং হ্যান্ডেল করার জন্য দুটি বিল্ট-ইন অপশন দিয়ে আসে: প্রিন্টিং কমান্ডস (কম্যांड-লাইন সিনেরিওর জন্য বিশেষভাবে ডিজাইন করা) এবং Logger ক্লাস।
চলুন এগুলো একটু এক্সপ্লোর করি।
কনসোলে প্রিন্ট
রুবিতে কনসোলে টেক্সট প্রিন্ট করার চারটি সাধারণ উপায় আছে: puts, print, p, এবং pp।
puts মেথড আপনি যা পাস করবেন সেটি প্রিন্ট করে, তারপর একটি নিউ লাইন:
2.7.0 :001 > puts "Hey, I'm a log!"
Hey, I'm a log!
=> nil
print মেথড puts-এর মত, তবে এটি সবসময় আর্গুমেন্টগুলোকে to_s মেথড দিয়ে স্ট্রিংএ কনভার্ট করে।
শেষে, p এবং pp মেথড দুটোই আপনি যে র オブজেক্ট পাস করছেন সেটি কোনো কনভারশন ছাড়া র আকারে প্রিন্ট করে; একমাত্র পার্থক্য হলো পরেরটি আউটপুটকে আরও ইন্ডেন্টেড ফরম্যাটে ফরম্যাট করে, প্রথমটি না।
অ্যাপ্লিকেশন লগ
সার্ভারে রান হওয়া অ্যাপ্লিকেশনের জন্য, কনসোলে প্রিন্ট করা অর্থহীন।
বরং, আমরা Logger ক্লাস ব্যবহার করি, যা অনেক বেশি ফ্লেক্সিবল।
এখানে দেখানো হলো কীভাবে আপনি একটি "debug" লগ প্রিন্ট করতে পারেন:
require "logger"
logger = Logger.new(STDOUT)
logger.debug("I'm a debug log")
আমরা এটিকে কনফিগারও করতে পারি লগগুলো একটি ফাইলে সংরক্ষণ করার জন্য, অথবা প্রিন্ট করার বদলে একটি লগ অ্যাগ্রিগেটরে পাঠাতে।
আপনি যদি কৌতুহলী হন, "debug" হলো একটি লগ লেভেল। লগ লেভেলগুলো আপনাকে সিস্টেমকে বলতে দেয় "এই লগ মেসেজটি একটি নির্দিষ্ট ধরণের ইভেন্টের সাথে সম্পর্কিত।" ছয়টি বিল্ট-ইন লগ লেভেল আছে: Fatal, Error, Warn, Info, Debug এবং Unknown।
logger.debug("I'm a debug log")
logger.info("I'm an info log")
logger.warn("I'm a warn log")
logger.error("I'm an error log: error message")
logger.fatal("I'm a fatal log")
যখন আমরা লগ আউটপুট দেখি, লগ লেভেল, প্রসেস আইডি, এবং টাইমস্ট্যাম্প প্রতিটি লাইনে অ্যাপেন্ড হয়ে থাকা দেখা যায়:

একটা অন্য দারুণ ফিচার হলো আপনার Logger অবজেক্টকে একটি স্পেসিফিক লেভেলে সেট করার ক্ষমতা:
logger.level = Logger::WARN
যখন আপনি এটা করেন, Logger শুধু warn-এ সমান বা তার চেয়ে বেশি গুরুত্বপূর্ণ লগগুলো হ্যান্ডেল করবে। এটি প্রোডাকশনে খুব উপকারী, যেখানে আমরা "debug" লগ সংরক্ষণ করতে চাই না সাইজ বা সিকিউরিটি কারণ。
এটি আউটপুট হওয়া উচিত:

আপনার লগ কাস্টোমাইজ
আপনি যদি আপনার লগ কাস্টোমাইজ করতে চান, তাহলে অপশনগুলোর অভাব নেই। ডেট এবং টাইম পরিবর্তন করতে চাইলে, ডিফল্টটিকে ওভাররাইট করুন:
logger.datetime_format = "%Y-%m-%d %H:%M"
আউটপুট উদাহরণ:
W, [2020-07-28 10:50#87786] WARN -- : I'm a warn log
date_time ফরম্যাট স্ট্যান্ডার্ড স্পেসিফিকেশন ফলো করে, তাই সেটি রেফার করুন τέ parecido পরিবর্তন করার সময়।
কখনো কখনো, যাইহোক, আপনাকে আপনার লগের ফরম্যাট সম্পূর্ণরূপে মডিফাই করতে হতে পারে। এই উদ্দেশ্যে, রুবি Formatter ক্লাস প্রদান করে। এটি ডেভেলপারদের ডিফল্ট টেমপ্লেট ওভাররাইট করার অনুমতি দিয়ে কাজ করে যা Logger লগ প্রিন্ট করার জন্য ব্যবহার করে।
কল্পনা করুন আপনার অ্যাপ একটি সেন্ট্রালাইজড লগস অ্যানালাইসিস টুল ব্যবহার করে এবং আপনার সব লগ name=value ফরম্যাটে প্রিন্ট করতে চায়। এটা হলে নতুন ফরম্যাটার কোড:
logger.formatter = proc do |severity, datetime, progname, msg|
date_format = datetime.strftime("%Y-%m-%d %H:%M:%S")
"date=[#{date_format}] severity=#{severity.ljust(5)} pid=##{Process.pid} message='#{msg}'\n"
end
এখানে, আমরা একটি proc ব্যবহার করছি সব লগ ইন্টারসেপ্ট করতে এবং ডিফল্ট প্রিন্টিং পদ্ধতিকে আমাদের পছন্দসই পদ্ধতিতে পরিবর্তন করতে। এখন, আমাদের নিচের ফলাফল:

সिर्फ কয়েক লাইন কোডে, আপনার সকল অ্যাপ লগ টুল দ্বারা ইন্ডেক্স করা যাবে।
JSON-এ লগিং
Formatter-এর শক্তি হাতে থাকলে, আপনার লগগুলো যেকোনো আউটপুট টাইপে কাস্টোমাইজ করা সহজ। উদাহরণস্বরূপ, আমরা JSON মডিউল ব্যবহার করে আমাদের লগগুলো JSON ফরম্যাটে আউটপুট করতে পারি।
require "json"
logger.formatter = proc do |severity, datetime, progname, msg|
date_format = datetime.strftime("%Y-%m-%d %H:%M:%S")
JSON.dump(date: "#{date_format}", severity:"#{severity.ljust(5)}", pid:"##{Process.pid}", message: msg) + "\n"
end
এবং, ফলাফল লগগুলো:

ফাইলে লগিং
পূর্বে দেখা গিয়েছে, Logger কনস্ট্রাক্টর প্রথম আর্গুমেন্ট হিসেবে লগ সংরক্ষণ করার জায়গা নেয়।
আপনি যদি লগগুলো ফাইলে সংরক্ষণ করতে চান, শুধু বলুন:
require 'logger'
logger = Logger.new('my_logs.log')
এটি একই ফোল্ডারে my_logs.log নামে একটি নতুন ফাইল তৈরি করবে যেখানে আপনার এই কোডবিশিষ্ট রুবি ফাইলটি অবস্থিত:

তবে, ক্লাসটি অনেক কাস্টোম অপশনও অনুমতি দেয়, যেমন রিটেনশন পলিসি কনফিগ। নিচের উদাহরণ দেখুন:
# বর্তমান সপ্তাহের ডেটা রাখুন।
Logger.new('my_weekly_logs.log', 'weekly')
# আজ এবং গত ২ মাসের ডেটা রাখুন।
Logger.new('my_latest_2_months_logs.log', 2, 'monthly')
# ২৬GB সাইজ অতিক্রম করলে লগ রিস্টার্ট।
Logger.new('my_custom_logs.log', 0, 20 * 1024 * 1024 * 1024)
দ্বিতীয় প্যারামিটার হিসেবে, Logger একটি ডেফিনিশন গ্রহণ করে কতক্ষণ লগ রাখবে বা মুছে ফেলবে।
প্রথম অবজেক্টে, লগ এক সপ্তাহ রাখা হবে। দ্বিতীয়ে দু মাসের রেঞ্জে স্টোর হবে, আর শেষটি শুধু ফাইল সাইজ বিশ্লেষণ করবে (যেমন, যখনই ২০GB-এ পৌঁছাবে, এটিকে ডিসকার্ড করা হবে) তৃতীয় প্যারামিটার অনুযায়ী।
রুবি অন রেইলসে লগিং
Logger-এর অধিকাংশ সুবিধা যা আমরা এতক্ষণ দেখেছি, সবই রেইলস অ্যাপসের সাথে ব্যবহার করা যায়। রেইলস ভার্সনের Logger কেবল রুবির নেটিভ ক্লাসের একটি সিম্পল এক্সটেনশন।
সেটি ছাড়াও, রেইলস একটি সুন্দর ফিচার যোগ করে যা ডেভেলপারদের তাদের লগ একাধিক লগারে ব্রডকাস্ট করার অনুমতি দেয়। সুতরাং, যদি আপনি একাধিক লগিং লাইব্রেরি সাথে কাজ করতে চান, তবে রেইলস logger-এ করতে পারেন:
custom_logger = Logger.new(STDOUT)
Rails.logger.extend(ActiveSupport::Logger.broadcast(custom_logger))
এটি তখনও উপকারী হতে পারে যখন আপনাকে লগগুলোর প্লেসমেন্ট সম্পর্কে কিছু ইন্টেলিজেন্স দরকার। আপনার অ্যাপের কিছু অংশে লগ別ের লোকেশন বা আলাদা ফরম্যাটে দরকার হতে পারে।
থার্ড-পার্টি লগিং ফ্রেমওয়ার্ক বেছে নেওয়া
রুবির বিল্ট-ইন লগার আপনার যা দরকার সেটি এক্স্যাক্টলি না করলে, আপনার অপশন আছে।
থার্ড-পার্টি লগিং ফ্রেমওয়ার্ক বেছে নেওয়ার ক্ষেত্রে অপশনগুলোর অভাব নেই। সবচেয়ে জনপ্রিয়টি হলো Lograge। চলুন এটাকে এক নজর দেখি!
Lograge সহ প্রথম পদক্ষেপ
Lograge রেইলস অ্যাপের জন্য তৈরি। আপনি যদি ভ্যানিলা রুবি নিয়ে কাজ করেন, তবে এটা ভালো চয়েস নয়।
ইনস্টল করতে, শুধু নিচের জেম যোগ করুন:
bundle add lograge
তারপর, config/initializers/lograge.rb এ একটি নতুন কনফিগ ফাইল তৈরি করুন নিচের কোড সহ:
Rails.application.configure do
config.lograge.enabled = true
config.lograge.custom_options = lambda do |event|
{ time: event.time }
end
end
এই কনফিগ Lograge ইন্যাবল করে এবং একটি লগকে, যেটি ফ্রেমওয়ার্কের জন্য একটি ইভেন্ট, কখন প্রিন্ট হবে সেটি ডিফাইন করে।
রেইলস অ্যাপ স্টার্ট করলে এবং প্রথম এন্ডপয়েন্ট এক্সেস করলে, Lograge রিকোয়েস্ট সামারি প্রিন্ট করবে। Lograge সেটআপ করার আগে এবং পরে লগগুলো তুলনা করলে, যথাক্রমে নিচের ফলাফল আসবে:

আবার বলছি, Lograge সিল्वर বুলেট নয়; এটি আসলে একটি ভাবি অপিনিয়নেটেড ফ্রেমওয়ার্ক। তাই, আপনি সম্ভবত এটিকে বিল্ট-ইন Logger (অথবা আপনার পছন্দের অন্যান্য ফ্রেমওয়ার্ক) সাথে ব্যবহার করবেন।
উপসংহার
শেষে, এটি স্পষ্ট হয়ে যায় যে লগিং শুধু আপনার প্রজেক্টের একটি গুরুত্বপূর্ণ অংশ নয়, বরং খুব অন্ডারএস্টিমেটেড (underestimated) ও। আপনি যে টুলস ব্যবহার করছেন সেগুলো ভালোভাবে বুঝতে, না নেটিভ হোক না থার্ড-পার্টি, আপনাকে আরও ভালো ফলাফল অর্জনে সাহায্য করবে।
নিশ্চিত করুন আপনি একটি নতুন ফ্রেমওয়ার্ক এডপ্ট করার আগে খুব সারצות টেস্টিং করছেন। কখনো কখনো আপনার প্ল্যাটফর্ম ইতিমধ্যে চমৎকার বিল্ট-ইন অপশন নিয়ে আসে। যদি না হয়, তবে নির্ধারণ করুন কি এটি ইতিমধ্যে আছে সেটির সাথে অন্য ফ্রেমওয়ার্ক ইন্টিগ্রেট করার অনুমতি দেয়।
শুভকামনা!