From c50531589d6f2cfdb703e3387c3f13020146be66 Mon Sep 17 00:00:00 2001 From: Takayuki Murooka Date: Wed, 11 Dec 2024 00:48:21 +0900 Subject: [PATCH 1/3] feat(autoware_debug_tools): add frequent_log_checker.py Signed-off-by: Takayuki Murooka --- common/autoware_debug_tools/README.md | 17 +++ .../frequent_log_checker.py | 107 ++++++++++++++++++ common/autoware_debug_tools/setup.py | 1 + 3 files changed, 125 insertions(+) create mode 100755 common/autoware_debug_tools/autoware_debug_tools/frequent_log_checker.py diff --git a/common/autoware_debug_tools/README.md b/common/autoware_debug_tools/README.md index f06c3540..a102e550 100644 --- a/common/autoware_debug_tools/README.md +++ b/common/autoware_debug_tools/README.md @@ -119,3 +119,20 @@ ros2 run autoware_debug_tools rosout_log_reconstructor ``` ![rosout_log_example](images/rosout_log_example.png) + +## Frequent Log Checker + +This script shows the frequent log from the `launch.log`. +In detail, the log which appears more than the threshold times during the duration will be shown. + +### Usage + +```bash +ros2 run autoware_debug_tools frequent_log_checker +``` + +The command options are + +- `-d`: duration to check the frequent log +- `-c`: threshold of the log count during the duration +- `-f`: log format. Several log formats are pre-defined in the script. diff --git a/common/autoware_debug_tools/autoware_debug_tools/frequent_log_checker.py b/common/autoware_debug_tools/autoware_debug_tools/frequent_log_checker.py new file mode 100755 index 00000000..44db181d --- /dev/null +++ b/common/autoware_debug_tools/autoware_debug_tools/frequent_log_checker.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 + +# Copyright 2024 TIER IV, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import argparse + + +class Log: + def __init__(self, node_name, timestamp, content, file_and_line, full_message): + self.node_name = node_name + self.timestamp = timestamp + self.content = content + self.file_and_line = file_and_line + self.full_message = full_message + + def is_same(self, log): + return self.node_name == log.node_name and self.file_and_line == log.file_and_line + + def is_in(self, log_list): + for target_log in log_list: + if self.is_same(target_log): + return True + return False + + +def check(log_file, duration_to_check, log_count_threshold, log_format): + recent_log_list = [] + unique_frequent_log_list = [] + + # with open("autoware.log", "r") as f: + with open(log_file, "r") as f: + for full_message in f.readlines(): + try: + if log_format == "1": + node_name = full_message.split("[")[4].split("]")[0] + timestamp = float(full_message.split("[")[0][:-1]) + content = full_message.split("]")[3].split(" at ")[0] + file_and_line = full_message.split("]")[3].split(" at ")[1] + recent_log = Log(node_name, timestamp, content, file_and_line, full_message) + elif log_format == "2": + node_name = full_message.split("]")[0][1:] + timestamp = float(full_message.split("]")[1].split(" ")[2]) + content = full_message.split("]")[3].split(" at ")[0] + file_and_line = full_message.split("]")[3].split(" at ")[1] + recent_log = Log(node_name, timestamp, content, file_and_line, full_message) + else: + continue + except IndexError: + continue + except ValueError: + continue + + # skip if the log is already considered as frequent + if recent_log.is_in(unique_frequent_log_list): + continue + recent_log_list.append(recent_log) + + # remove obsolete or already frequent log + for log in recent_log_list[:]: + duration = timestamp - log.timestamp + if duration_to_check < duration: + recent_log_list.remove(log) + + # extract duplicated (= frequent) log + for i in range(len(recent_log_list)): + log_count = 0 + if recent_log_list[i].is_in(unique_frequent_log_list): + continue + + for j in range(len(recent_log_list)): + if i <= j: + continue + if recent_log_list[i].is_same(recent_log_list[j]): + log_count += 1 + + if log_count_threshold <= log_count: + unique_frequent_log_list.append(recent_log_list[i]) + + for frequent_log in unique_frequent_log_list: + print(frequent_log.full_message) + + +def main(): + parser = argparse.ArgumentParser(description="frequent log checker") + parser.add_argument("log_file", help="launch log file") + parser.add_argument("-d", "--log-duration", default=1.0, help="duration to check log") + parser.add_argument("-c", "--log-count", default=2, help="log count threshold") + parser.add_argument("-f", "--log-format", default="1", help="log format") + args = parser.parse_args() + + check(args.log_file, args.log_duration, args.log_count, args.log_format) + + +if __name__ == "__main__": + main() diff --git a/common/autoware_debug_tools/setup.py b/common/autoware_debug_tools/setup.py index bd2fb9d0..41970178 100644 --- a/common/autoware_debug_tools/setup.py +++ b/common/autoware_debug_tools/setup.py @@ -28,6 +28,7 @@ "topic_connection_checker = autoware_debug_tools.topic_connection_checker.topic_connection_checker_node:main", "topic_localizer = autoware_debug_tools.topic_connection_checker.localize_topic:main", "rosout_log_reconstructor = autoware_debug_tools.rosout_log_reconstructor:main", + "frequent_log_checker = autoware_debug_tools.frequent_log_checker:main", ], }, ) From af55b450a1a67dd00ef5b3befef8353967c82cbe Mon Sep 17 00:00:00 2001 From: Takayuki Murooka Date: Wed, 11 Dec 2024 00:53:57 +0900 Subject: [PATCH 2/3] minor change Signed-off-by: Takayuki Murooka --- common/autoware_debug_tools/README.md | 8 ++++---- .../autoware_debug_tools/frequent_log_checker.py | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/common/autoware_debug_tools/README.md b/common/autoware_debug_tools/README.md index a102e550..62d0119e 100644 --- a/common/autoware_debug_tools/README.md +++ b/common/autoware_debug_tools/README.md @@ -123,16 +123,16 @@ ros2 run autoware_debug_tools rosout_log_reconstructor ## Frequent Log Checker This script shows the frequent log from the `launch.log`. -In detail, the log which appears more than the threshold times during the duration will be shown. +In detail, the log which appears more than the threshold times during the duration will be list down. ### Usage ```bash -ros2 run autoware_debug_tools frequent_log_checker +ros2 run autoware_debug_tools frequent_log_checker ``` -The command options are +The command has following options. -- `-d`: duration to check the frequent log +- `-d`: duration to count the number of log - `-c`: threshold of the log count during the duration - `-f`: log format. Several log formats are pre-defined in the script. diff --git a/common/autoware_debug_tools/autoware_debug_tools/frequent_log_checker.py b/common/autoware_debug_tools/autoware_debug_tools/frequent_log_checker.py index 44db181d..487d3909 100755 --- a/common/autoware_debug_tools/autoware_debug_tools/frequent_log_checker.py +++ b/common/autoware_debug_tools/autoware_debug_tools/frequent_log_checker.py @@ -35,7 +35,7 @@ def is_in(self, log_list): return False -def check(log_file, duration_to_check, log_count_threshold, log_format): +def check(log_file, duration_to_count, log_count_threshold, log_format): recent_log_list = [] unique_frequent_log_list = [] @@ -70,7 +70,7 @@ def check(log_file, duration_to_check, log_count_threshold, log_format): # remove obsolete or already frequent log for log in recent_log_list[:]: duration = timestamp - log.timestamp - if duration_to_check < duration: + if duration_to_count < duration: recent_log_list.remove(log) # extract duplicated (= frequent) log @@ -95,7 +95,7 @@ def check(log_file, duration_to_check, log_count_threshold, log_format): def main(): parser = argparse.ArgumentParser(description="frequent log checker") parser.add_argument("log_file", help="launch log file") - parser.add_argument("-d", "--log-duration", default=1.0, help="duration to check log") + parser.add_argument("-d", "--log-duration", default=1.0, help="duration to count log") parser.add_argument("-c", "--log-count", default=2, help="log count threshold") parser.add_argument("-f", "--log-format", default="1", help="log format") args = parser.parse_args() From d7a3c327af208e0766944bdceee8e89d037a9507 Mon Sep 17 00:00:00 2001 From: Takayuki Murooka Date: Wed, 11 Dec 2024 01:31:06 +0900 Subject: [PATCH 3/3] minor fix Signed-off-by: Takayuki Murooka --- .../autoware_debug_tools/frequent_log_checker.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/common/autoware_debug_tools/autoware_debug_tools/frequent_log_checker.py b/common/autoware_debug_tools/autoware_debug_tools/frequent_log_checker.py index 487d3909..2f06e33d 100755 --- a/common/autoware_debug_tools/autoware_debug_tools/frequent_log_checker.py +++ b/common/autoware_debug_tools/autoware_debug_tools/frequent_log_checker.py @@ -39,10 +39,10 @@ def check(log_file, duration_to_count, log_count_threshold, log_format): recent_log_list = [] unique_frequent_log_list = [] - # with open("autoware.log", "r") as f: with open(log_file, "r") as f: for full_message in f.readlines(): try: + # The following implementation depends on the log format. if log_format == "1": node_name = full_message.split("[")[4].split("]")[0] timestamp = float(full_message.split("[")[0][:-1]) @@ -88,8 +88,13 @@ def check(log_file, duration_to_count, log_count_threshold, log_format): if log_count_threshold <= log_count: unique_frequent_log_list.append(recent_log_list[i]) - for frequent_log in unique_frequent_log_list: - print(frequent_log.full_message) + if len(unique_frequent_log_list) == 0: + print( + "No frequent log. The log format designated by the `-f` option may be different from the actual log format." + ) + else: + for frequent_log in unique_frequent_log_list: + print(frequent_log.full_message) def main():