প্রোটোলগ

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

WindowManager এবং অনুরূপ সার্ভিসগুলোর লগিং চাহিদা মেটানোর জন্য ProtoLog একটি বিকল্প। Logcat-এর তুলনায় ProtoLog নিম্নলিখিত সুবিধাগুলো প্রদান করে:

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

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

প্রোটোলগ একটি পারফেটটো ট্রেসের মধ্যে মেসেজগুলোকে বাইনারি ফরম্যাটে (প্রোটো) সংরক্ষণ করে। মেসেজ ডিকোডিং পারফেটটোর trace_processor মধ্যে সম্পন্ন হয়। এই প্রসেসটি বাইনারি প্রোটো মেসেজগুলোকে ডিকোড করে, এমবেডেড মেসেজ ডিকশনারি ব্যবহার করে মেসেজ আইডেন্টিফায়ারগুলোকে স্ট্রিং-এ অনুবাদ করে এবং ডাইনামিক আর্গুমেন্ট ব্যবহার করে স্ট্রিংটিকে ফরম্যাট করে।

ProtoLog, android.utils.Log মতোই একই লগ লেভেলগুলো সমর্থন করে, যেগুলো হলো d , v , i , w , e এবং wtf

ক্লায়েন্ট-সাইড প্রোটোলগ

প্রাথমিকভাবে, ProtoLog শুধুমাত্র WindowManager-এর সার্ভার সাইডের জন্য তৈরি করা হয়েছিল, যা একটি একক প্রসেস এবং কম্পোনেন্টের মধ্যে কাজ করত। পরবর্তীতে, System UI প্রসেসের WindowManager শেল কোডকেও এর অন্তর্ভুক্ত করার জন্য এর পরিধি বাড়ানো হয়। তবে, ProtoLog ব্যবহার করার জন্য জটিল বয়লারপ্লেট সেটআপ কোডের প্রয়োজন হতো। এছাড়াও, প্রোটো লগিং শুধুমাত্র সিস্টেম সার্ভার এবং System UI প্রসেসের মধ্যেই সীমাবদ্ধ ছিল। এর ফলে এটিকে অন্যান্য প্রসেসের সাথে যুক্ত করা কঠিন হয়ে পড়ে এবং প্রতিটির জন্য আলাদা মেমরি বাফার সেটআপের প্রয়োজন হতো। ProtoLog এখন ক্লায়েন্ট-সাইড কোডের জন্যও উপলব্ধ, যার ফলে অতিরিক্ত বয়লারপ্লেট কোডের প্রয়োজনীয়তা দূর হয়েছে।

সিস্টেম সার্ভিসেস কোডের বিপরীতে, ক্লায়েন্ট-সাইড কোড সাধারণত কম্পাইল-টাইম স্ট্রিং ইন্টার্নিং এড়িয়ে যায়। এর পরিবর্তে, স্ট্রিং ইন্টার্নিং একটি ব্যাকগ্রাউন্ড থ্রেডে ডায়নামিকভাবে সম্পন্ন হয়। ফলস্বরূপ, যদিও ক্লায়েন্ট-সাইড প্রোটোলগ সিস্টেম সার্ভিসেসের প্রোটোলগের সমতুল্য মেমরি ব্যবহারের সুবিধা প্রদান করে, এটি কিছুটা বেশি পারফরম্যান্স ওভারহেড তৈরি করে এবং এর সার্ভার-সাইড সংস্করণের মতো পিনড মেমরির মাধ্যমে মেমরি হ্রাসের সুবিধা এতে থাকে না।

প্রোটোলগ গ্রুপ

ProtoLog বার্তাগুলিকে ProtoLogGroups নামক গ্রুপে সংগঠিত করা হয়, ঠিক যেমনভাবে Logcat বার্তাগুলিকে TAG দ্বারা সংগঠিত করা হয়। এই ProtoLogGroups বার্তা ক্লাস্টার হিসাবে কাজ করে যা আপনি রানটাইমে সক্রিয় বা নিষ্ক্রিয় করতে পারেন। এগুলি আরও নিয়ন্ত্রণ করে যে কম্পাইলেশনের সময় বার্তাগুলি স্ট্রিপ করা হবে কিনা এবং সেগুলি কোথায় লগ করা হবে (প্রোটো, লগক্যাট, বা উভয়ই)। প্রতিটি ProtoLogGroup নিম্নলিখিত বৈশিষ্ট্যগুলি অন্তর্ভুক্ত থাকে:

  • enabled : যখন এর মান false সেট করা হয়, তখন এই গ্রুপের বার্তাগুলি কম্পাইলেশনের সময় বাদ দেওয়া হয় এবং রানটাইমে উপলব্ধ থাকে না।
  • logToProto : এই গ্রুপটি বাইনারি ফরম্যাটে লগ করবে কিনা তা নির্ধারণ করে।
  • logToLogcat : এই গ্রুপটি লগক্যাটে লগ করবে কিনা তা নির্ধারণ করে।
  • tag : লগ করা বার্তার উৎসের নাম।

ProtoLog ব্যবহারকারী প্রতিটি প্রসেসের জন্য একটি ProtoLogGroup ইনস্ট্যান্স কনফিগার করা আবশ্যক।

সমর্থিত আর্গুমেন্টের প্রকারভেদ

ProtoLog অভ্যন্তরীণভাবে android.text.TextUtils#formatSimple(String, Object...) ব্যবহার করে স্ট্রিং ফরম্যাট করে, তাই এর সিনট্যাক্স একই।

ProtoLog নিম্নলিখিত আর্গুমেন্ট প্রকারগুলি সমর্থন করে:

  • %b - বুলিয়ান
  • %d , %x - পূর্ণসংখ্যা প্রকার (শর্ট, ইন্টিজার, বা লং)
  • %f - ফ্লোটিং পয়েন্ট টাইপ (ফ্লোট বা ডাবল)
  • %s - স্ট্রিং
  • %% - একটি আক্ষরিক শতাংশ চিহ্ন

প্রস্থ এবং নির্ভুলতা মডিফায়ার, যেমন %04d এবং %10b , সমর্থিত। তবে, argument_index এবং flags সমর্থিত নয়।

একটি নতুন পরিষেবাতে ProtoLog ব্যবহার করুন

একটি নতুন পরিষেবাতে ProtoLog ব্যবহার করতে, এই ধাপগুলি অনুসরণ করুন:

  1. এই সার্ভিসের জন্য একটি ProtoLogGroup ডেফিনিশন তৈরি করুন।
  2. প্রথমবার ব্যবহারের আগে ডেফিনিশনটি ইনিশিয়ালাইজ করুন। উদাহরণস্বরূপ, প্রসেস তৈরির সময় এটি ইনিশিয়ালাইজ করুন:

    ProtoLog.init(ProtoLogGroup.values());
    
  3. android.util.Log যেভাবে ব্যবহার করেন, ProtoLog ঠিক সেভাবেই ব্যবহার করুন:

    ProtoLog.v(WM_SHELL_STARTING_WINDOW, "create taskSnapshot surface for task: %d", taskId);
    

কম্পাইল-টাইম অপ্টিমাইজেশন সক্ষম করুন

কোনো প্রসেসে কম্পাইল-টাইম প্রোটোলগ সক্রিয় করতে হলে, আপনাকে এর বিল্ড রুলস পরিবর্তন করতে হবে এবং 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 গ্রুপগুলো বিভিন্ন ধরনের ট্রানজিশন লগিং সক্রিয় করে, যার মধ্যে প্রথমটি ডিফল্টরূপে সক্রিয় থাকে।

ট্রেস শুরু করার সময় আপনি পারফেটটো ব্যবহার করে প্রোটোলগ কনফিগার করতে পারেন। এছাড়াও, আপনি adb কমান্ড লাইন ব্যবহার করে স্থানীয়ভাবে প্রোটোলগ কনফিগার করতে পারেন।

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)

এই ক্রমটির ফলে মেমোরি ফুটপ্রিন্ট ৩৫% ছোট হয়।

উইনস্কোপ ভিউয়ার

উইনস্কোপের প্রোটোলগ ভিউয়ার ট্যাবটি প্রোটোলগ ট্রেসগুলোকে একটি সারণী আকারে সাজিয়ে দেখায়। আপনি লগ লেভেল, ট্যাগ, সোর্স ফাইল (যেখানে প্রোটোলগ স্টেটমেন্টটি রয়েছে) এবং মেসেজের বিষয়বস্তু অনুযায়ী ট্রেসগুলো ফিল্টার করতে পারেন। সমস্ত কলামই ফিল্টারযোগ্য। প্রথম কলামের টাইমস্ট্যাম্পে ক্লিক করলে টাইমলাইনটি মেসেজের টাইমস্ট্যাম্পে চলে যায়। এছাড়াও, 'Go to Current Time'-এ ক্লিক করলে প্রোটোলগ টেবিলটি স্ক্রল করে টাইমলাইনে নির্বাচিত টাইমস্ট্যাম্পে ফিরে আসে।

ProtoLog viewer

চিত্র ১. প্রোটোলগ ভিউয়ার