Android লগিং সিস্টেমের লক্ষ্য হল সর্বজনীন অ্যাক্সেসিবিলিটি এবং ব্যবহারের সুবিধা অর্জন করা, ধরে নেওয়া হয় যে সমস্ত লগ ডেটা অক্ষরের ক্রম হিসাবে উপস্থাপন করা যেতে পারে। এই অনুমানটি বেশিরভাগ ব্যবহারের ক্ষেত্রে প্রযোজ্য, বিশেষ করে যখন বিশেষ টুল ছাড়াই লগ রিডএবিলিটি গুরুত্বপূর্ণ। তবে, যেসব এনভায়রনমেন্টে হাই লগিং পারফর্ম্যান্স এবং সীমিত লগ সাইজের প্রয়োজন হয়, সেখানে টেক্সট-ভিত্তিক লগিং অপ্টিমাল নয়। এরকম একটি পরিস্থিতি হল WindowManager, যার জন্য একটি শক্তিশালী লগিং সিস্টেম প্রয়োজন যা সিস্টেমের উপর ন্যূনতম প্রভাব সহ রিয়েল-টাইম উইন্ডো ট্রানজিশন লগ ম্যানেজ করে।
WindowManager এবং এই ধরনের পরিষেবার লগিং সংক্রান্ত প্রয়োজনীয়তা পূরণের বিকল্প হল ProtoLog। ProtoLog, logcat-এর তুলনায় নিম্নলিখিত সুবিধাগুলি প্রদান করে:
- লগিংয়ের জন্য কম রিসোর্স ব্যবহার করে।
- ডেভেলপারদের দৃষ্টিকোণ থেকে, এটি ডিফল্ট Android লগিং ফ্রেমওয়ার্কের মতোই কাজ করে।
- রানটাইমে লগ স্টেটমেন্ট চালু বা বন্ধ করতে দেয়।
- logcat-এও লগ করতে পারে।
মেমরি ব্যবহার অপ্টিমাইজ করতে, ProtoLog একটি স্ট্রিং ইন্টার্নিং মেকানিজম ব্যবহার করে। এই মেকানিজম মেসেজের একটি কম্পাইল করা হ্যাশ গণনা করে ও সেভ করে। পারফর্ম্যান্স উন্নত করতে, ProtoLog সিস্টেম পরিষেবার জন্য কম্পাইলেশনের সময় স্ট্রিং ইন্টার্নিং করে। এটি রানটাইমে শুধুমাত্র মেসেজ শনাক্তকারী ও আর্গুমেন্ট রেকর্ড করে। আপনি ProtoLog ট্রেস তৈরি করলে বা সমস্যা সম্পর্কিত রিপোর্ট পেলে, ProtoLog অটোমেটিক কম্পাইল করার সময় তৈরি হওয়া মেসেজ ডিকশনারি অন্তর্ভুক্ত করে। এটি যেকোনও বিল্ড থেকে মেসেজ ডিকোড করার সুবিধা চালু করে।
ProtoLog, Perfetto ট্রেসের মধ্যে বাইনারি ফর্ম্যাটে (proto) মেসেজ স্টোর করে।
Perfetto-এর trace_processor-এর মধ্যে মেসেজ ডিকোড করা হয়। এই প্রসেস বাইনারি প্রোটো মেসেজকে
ডিকোড করে, এমবেড করা মেসেজ ডিকশনারি ব্যবহার করে মেসেজ আইডেন্টিফায়ারকে
স্ট্রিংয়ে ট্রান্সলেট করে এবং ডায়নামিক আর্গুমেন্ট ব্যবহার করে স্ট্রিংকে ফর্ম্যাট করে।
ProtoLog android.utils.Log-এর মতো একই লগ লেভেল কাজ করে, সেগুলি হল d,
v, i, w, e ও wtf.
ক্লায়েন্ট-সাইড ProtoLog
প্রাথমিকভাবে, ProtoLog শুধুমাত্র WindowManager-এর সার্ভার সাইডের জন্য তৈরি করা হয়েছিল, যা একটি প্রসেস ও কম্পোনেন্টের মধ্যে কাজ করে। পরে, এটি সিস্টেম UI প্রসেসে WindowManager শেল কোডকে অন্তর্ভুক্ত করার জন্য প্রসারিত করা হয়েছিল। তবে, ProtoLog ব্যবহার করার জন্য জটিল বয়লারপ্লেট সেট-আপ কোড প্রয়োজন। এছাড়াও, Proto লগিং সিস্টেম সার্ভার ও সিস্টেম UI প্রসেসে সীমাবদ্ধ ছিল। এর ফলে অন্যান্য প্রসেসে ইনকর্পোরেট করা কঠিন হয়ে পড়ে এবং প্রতিটি প্রসেসের জন্য আলাদা মেমরি বাফার সেট-আপ করতে হয়। ProtoLog এখন ক্লায়েন্ট-সাইড কোডের জন্য উপলভ্য, অতিরিক্ত বয়লারপ্লেট কোডের প্রয়োজনীয়তা দূর করে।
সিস্টেম সার্ভিস কোডের মতো নয়, ক্লায়েন্ট-সাইড কোড সাধারণত কম্পাইল-টাইম স্ট্রিং ইন্টার্নিং এড়িয়ে যায়। এর পরিবর্তে, ব্যাকগ্রাউন্ড থ্রেডে ডাইনামিকভাবে স্ট্রিং ইন্টার্নিং হয়। এর ফলে, ক্লায়েন্ট-সাইড ProtoLog, সিস্টেম পরিষেবায় ProtoLog-এর সাথে তুলনীয় মেমরি ব্যবহারের সুবিধা প্রদান করলেও, এটি সামান্য বেশি পারফর্ম্যান্স ওভারহেড তৈরি করে এবং পিন করা মেমরির মেমরি কমানোর সুবিধা এর মধ্যে থাকে না যা এর সার্ভার-সাইড সমকক্ষ অফার করে।
ProtoLog গ্রুপ
ProtoLog মেসেজকে ProtoLogGroups নামের গ্রুপে সাজানো হয়, এটি
Logcat মেসেজকে TAG-এর মাধ্যমে সাজানোর মতো। এই ProtoLogGroups
মেসেজ ক্লাস্টার হিসেবে কাজ করে যা আপনি রানটাইমে চালু বা বন্ধ করতে পারবেন। এছাড়াও, কম্পাইলেশনের সময় মেসেজ স্ট্রিপ করা হবে কিনা এবং কোথায় সেগুলি লগ করা হবে (প্রোটো, লগক্যাট বা দুটিই)
তা তারা নিয়ন্ত্রণ করে। প্রতিটি ProtoLogGroup-এ নিম্নলিখিত
প্রপার্টি থাকে:
enabled:falseহিসেবে সেট করা থাকলে, এই গ্রুপের মেসেজগুলি কম্পাইলেশনের সময় বাদ দেওয়া হয় এবং রানটাইমে উপলভ্য থাকে না।logToProto: এই গ্রুপ বাইনারি ফর্ম্যাটে লগ করে কিনা তা নির্ধারণ করে।logToLogcat: এই গ্রুপ logcat-এ লগ করবে কিনা তা নির্ধারণ করে।tag: লগ করা মেসেজের সোর্সের নাম।
ProtoLog ব্যবহার করে এমন প্রতিটি প্রসেসে অবশ্যই একটি ProtoLogGroup ইনস্ট্যান্স কনফিগার করা থাকতে হবে।
যেসব ধরনের আর্গুমেন্ট কাজ করে
ProtoLog ইন্টার্নালি android.text.TextUtils#formatSimple(String, Object...) ব্যবহার করে স্ট্রিং ফর্ম্যাট করে,
তাই এর সিনট্যাক্স একই।
ProtoLog-এ নিম্নলিখিত আর্গুমেন্টের ধরন কাজ করে:
%b- বুলিয়ান%d,%x- ইন্টিগ্রাল টাইপ (শর্ট, ইন্টিজার বা লং)%f- ফ্লোটিং পয়েন্টের ধরন (ফ্লোট বা ডবল)%s- string%%- আক্ষরিক শতাংশের চিহ্ন
%04d ও %10b-এর মতো প্রস্থ ও নির্ভুলতা পরিবর্তনকারী কাজ করে।
তবে, argument_index ও flags কাজ করে না।
নতুন পরিষেবায় ProtoLog ব্যবহার করা
নতুন কোনও পরিষেবায় ProtoLog ব্যবহার করতে, এইসব ধাপ অনুসরণ করুন:
- এই পরিষেবার জন্য
ProtoLogGroupসংজ্ঞা তৈরি করুন। প্রথমবার ব্যবহার করার আগে সংজ্ঞাটি ইনিশিয়ালাইজ করুন। যেমন, প্রসেস তৈরি করার সময় এটি শুরু করুন:
ProtoLog.init(ProtoLogGroup.values());android.util.Logযেভাবে ব্যবহার করেন, সেইভাবেইProtoLogব্যবহার করুন:ProtoLog.v(WM_SHELL_STARTING_WINDOW, "create taskSnapshot surface for task: %d", taskId);
কম্পাইল-টাইম অপ্টিমাইজেশন চালু করুন
কোনও প্রসেসে কম্পাইল-টাইম ProtoLog চালু করতে, আপনাকে অবশ্যই এর বিল্ড রুল পরিবর্তন করতে হবে
এবং protologtool বাইনারি ইনভোক করতে হবে।
ProtoLogTool হল একটি কোড ট্রান্সফর্মেশন বাইনারি যা স্ট্রিং ইন্টার্নিং পারফর্ম করে
এবং ProtoLog ইনভোকেশন আপডেট করে। এই বাইনারি প্রতিটি ProtoLog লগিং
কলকে এই উদাহরণে দেখানো পদ্ধতিতে ট্রান্সফর্ম করে:
ProtoLog.x(ProtoLogGroup.GROUP_NAME, "Format string %d %s", value1, value2);
এতে:
if (ProtoLogImpl.isEnabled(GROUP_NAME)) {
int protoLogParam0 = value1;
String protoLogParam1 = String.valueOf(value2);
ProtoLogImpl.x(ProtoLogGroup.GROUP_NAME, 1234560b0100, protoLogParam0, protoLogParam1);
}
এই উদাহরণে, ProtoLog, ProtoLogImpl ও ProtoLogGroup হল আর্গুমেন্ট হিসেবে দেওয়া
ক্লাস (ইমপোর্ট করা, স্ট্যাটিক ইমপোর্ট করা বা সম্পূর্ণ পাথ হতে পারে,
ওয়াইল্ডকার্ড ইমপোর্ট করার অনুমতি নেই) এবং x হল লগিং পদ্ধতি।
সোর্স লেভেলে ট্রান্সফর্মেশন করা হয়। ফর্ম্যাট স্ট্রিং, লগ লেভেল ও লগ গ্রুপের নাম থেকে হ্যাশ জেনারেট করা হয় এবং
ProtoLogGroup আর্গুমেন্টের পরে তা যোগ করা হয়। আসল জেনারেট করা কোড ইনলাইন করা হয় এবং ফাইলে লাইন নম্বর সেভ করার জন্য একাধিক নতুন
লাইন ক্যারেক্টার যোগ করা হয়।
উদাহরণ:
genrule {
name: "wm_shell_protolog_src",
srcs: [
":protolog-impl", // protolog lib
":wm_shell_protolog-groups", // protolog groups declaration
":wm_shell-sources", // source code
],
tools: ["protologtool"],
cmd: "$(location protologtool) transform-protolog-calls " +
"--protolog-class com.android.internal.protolog.ProtoLog " +
"--loggroups-class com.android.wm.shell.protolog.ShellProtoLogGroup " +
"--loggroups-jar $(location :wm_shell_protolog-groups) " +
"--viewer-config-file-path /system_ext/etc/wmshell.protolog.pb " +
"--legacy-viewer-config-file-path /system_ext/etc/wmshell.protolog.json.gz " +
"--legacy-output-file-path /data/misc/wmtrace/shell_log.winscope " +
"--output-srcjar $(out) " +
"$(locations :wm_shell-sources)",
out: ["wm_shell_protolog.srcjar"],
}
কমান্ড লাইন বিকল্প
ProtoLog-এর একটি প্রধান সুবিধা হল, আপনি রানটাইমে এটি চালু বা বন্ধ করতে
পারেন। যেমন, আপনি কোনও বিল্ডে আরও বিস্তারিত লগিং করতে পারেন, যা ডিফল্ট হিসেবে বন্ধ থাকে এবং কোনও নির্দিষ্ট
সমস্যা ডিবাগ করার জন্য লোকাল ডেভেলপমেন্টের সময় এটি চালু করা হয়।
এই প্যাটার্ন ব্যবহার করা হয়, যেমন, WindowManager-এ WM_DEBUG_WINDOW_TRANSITIONS এবং WM_DEBUG_WINDOW_TRANSITIONS_MIN গ্রুপের সাথে
বিভিন্ন ধরনের ট্রানজিশন লগিং চালু করা, যেখানে প্রথমটি ডিফল্ট হিসেবে চালু করা থাকে।
ট্রেস শুরু করার সময়, আপনি Perfetto ব্যবহার করে ProtoLog কনফিগার করতে পারবেন। এছাড়াও, আপনি adb কমান্ড লাইন ব্যবহার করে লোকালি ProtoLog কনফিগার করতে পারেন।
adb shell cmd protolog_configuration কমান্ড নিম্নলিখিত
আর্গুমেন্টগুলি সমর্থন করে:
help
Print this help text.
groups (list | status)
list - lists all ProtoLog groups registered with ProtoLog service"
status <group> - print the status of a ProtoLog group"
logcat (enable | disable) <group>"
enable or disable ProtoLog to logcat
কার্যকরভাবে ব্যবহার করার ব্যাপারে পরামর্শ
ProtoLog, মেসেজ ও পাস করা যেকোনও স্ট্রিং আর্গুমেন্টের জন্য স্ট্রিং ইন্টার্নিং ব্যবহার করে। এর অর্থ হল, ProtoLog থেকে আরও সুবিধা পেতে, মেসেজগুলিকে পুনরাবৃত্ত ভ্যালুগুলিকে ভেরিয়েবেলে আলাদা করতে হবে।
যেমন, নিম্নলিখিত বিবৃতিটি বিবেচনা করুন:
Protolog.v(MY_GROUP, "%s", "The argument value is " + argument);
কম্পাইল করার সময় অপ্টিমাইজ করা হলে, এটি এইভাবে অনুবাদ করা হয়:
ProtologImpl.v(MY_GROUP, 0x123, "The argument value is " + argument);
A,B,C আর্গুমেন্ট সহ কোডে ProtoLog ব্যবহার করা হলে:
Protolog.v(MY_GROUP, "%s", "The argument value is A");
Protolog.v(MY_GROUP, "%s", "The argument value is B");
Protolog.v(MY_GROUP, "%s", "The argument value is C");
Protolog.v(MY_GROUP, "%s", "The argument value is A");
এর ফলে মেমরিতে নিম্নলিখিত মেসেজ দেখা যায়:
Dict:
0x123: "%s"
0x111: "The argument value is A"
0x222: "The argument value is B"
0x333: "The argument value is C"
Message1 (Hash: 0x123, Arg1: 0x111)
Message2 (Hash: 0x123, Arg2: 0x222)
Message3 (Hash: 0x123, Arg3: 0x333)
Message4 (Hash: 0x123, Arg1: 0x111)
পরিবর্তে, ProtoLog বিবৃতিটি যদি এইভাবে লেখা হত:
Protolog.v(MY_GROUP, "The argument value is %s", argument);
ইন-মেমরি বাফার এইভাবে শেষ হবে:
Dict:
0x123: "The argument value is %s" (24 b)
0x111: "A" (1 b)
0x222: "B" (1 b)
0x333: "C" (1 b)
Message1 (Hash: 0x123, Arg1: 0x111)
Message2 (Hash: 0x123, Arg2: 0x222)
Message3 (Hash: 0x123, Arg3: 0x333)
Message4 (Hash: 0x123, Arg1: 0x111)
এই সিকোয়েন্সের ফলে মেমরি ফুটপ্রিন্ট ৩৫% ছোট হয়।
Winscope ভিউয়ার
Winscope-এর ProtoLog ভিউয়ার ট্যাব, সারণী ফর্ম্যাটে সাজানো ProtoLog ট্রেস দেখায়। আপনি লগ লেভেল, ট্যাগ, সোর্স ফাইল (যেখানে ProtoLog স্টেটমেন্ট আছে) এবং মেসেজ কন্টেন্ট অনুযায়ী ট্রেস ফিল্টার করতে পারবেন। সব কলাম ফিল্টার করা যায়। প্রথম কলামে টাইমস্ট্যাম্পে ক্লিক করলে টাইমলাইনটি মেসেজ টাইমস্ট্যাম্পে নিয়ে যাওয়া হয়। এছাড়াও, বর্তমান সময়ে যান বিকল্পে ক্লিক করলে, ProtoLog টেবিলটি টাইমলাইনে বেছে নেওয়া টাইমস্ট্যাম্পে ফিরে যায়:
ছবি ১. ProtoLog ভিউয়ার