Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moved logger to common #45

Merged
merged 39 commits into from
Aug 28, 2024
Merged

Moved logger to common #45

merged 39 commits into from
Aug 28, 2024

Conversation

AshishA26
Copy link
Contributor

@AshishA26 AshishA26 commented Aug 11, 2024

Moved logger to common.

PR must be merged before the PR in computer-vision-python UWARG/computer-vision-python#194.

@AshishA26 AshishA26 marked this pull request as draft August 11, 2024 00:51
@AshishA26 AshishA26 marked this pull request as ready for review August 16, 2024 23:57
Copy link
Contributor

@TongguangZhang TongguangZhang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reviewed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to read_yaml.py

Copy link
Member

@maxlou05 maxlou05 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comments. Also, would need to rebase to main after Python 3.11 fix is merged.

logging_path = pathlib.Path(log_directory_path, start_time)

# Create logging directory
pathlib.Path(log_directory_path).mkdir(exist_ok=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we want to have parent=True in case parent directories need to be created as well

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edit: Just set parent=True in the next line, and delete this one

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*reminder

logger/modules/logger_setup_main.py Outdated Show resolved Hide resolved
# pylint: disable-next=unused-import
import types

from read_yaml.modules import read_yaml
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This warrants some discussion. Since common is meant to be imported as a submodule, everything needs to be a relative import. This code will fail when being used as a submodule. However, because Python does not support sibling module imports, (ie you cannot import read_yaml from logger since they're both at the root level) this causes some problems. We must ensure that all top-level modules (like logger) are independent and do not depend upon anything other top-level modules. So we must put yaml_tools inside of logger. Then there is the question "what if another modules wants to use yaml tools?". (eg. camera_qr_example.py would not work if you tried to do py -m modules.common.camera_qr_example after importing common into airside)

  1. You can keep it as it is and manually edit all the imports when you use common in another project (since now common is no longer the root). (eg changing from camera.modules import ... to from .camera.modules import ... after initializing the common submodule, seems annoying and lot of effort)
  2. We can put everything in another folder (like common/tools), but then all of our imports will have an extra .tools, which may look ugly. (eg py -m modules.common.tools.camera_qr_example)
  3. We copy yaml_tools in all of the modules that needs it (this is sort of how dronekit is implemented currently, except only one of the modules, mavlink, needs dronekit)

Feel free to discuss, but this is an organizational issue we need to resolve

from read_yaml.modules import read_yaml


def main() -> int:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this not be tested with pytest? If all logger does is write to stdout and stderr, you should be able to test that using pytest. If so, I would recommend making this a pytest because at least I would be too lazy to manually run all these tests lmao. (I'm not too familiar with python's logging module)

@maxlou05 maxlou05 mentioned this pull request Aug 23, 2024
Copy link
Member

@maxlou05 maxlou05 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed some more

@@ -0,0 +1,5 @@
logger:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to have a link to documentation on the format strings

from read_yaml.modules import read_yaml


CONFIG_FILE_PATH = pathlib.Path("config_logger.yaml")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not checked, but I believe relative paths like this depend on where the command is executed. So similar to the relative imports issue, this would work if run from py -m common... (since you are in common folder) but will probably fail when running from py -m modules.common... (since you are in airside folder). Someone should test this, and I think using the __file__ variable can help in this situation.

logging_path = pathlib.Path(log_directory_path, start_time)

# Create logging directory
pathlib.Path(log_directory_path).mkdir(exist_ok=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edit: Just set parent=True in the next line, and delete this one

entries = os.listdir(log_directory_path)

if len(entries) == 0:
print("ERROR: Must create a new log directory for this run before starting logger")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than "log directory", which is confusing with the base "directory_path" from the yaml, we can say "No previous logging sessions available"

import inspect
import pytest

from logger.modules import logger
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same: relative path


import pathlib

from read_yaml.modules import read_yaml
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same: relative path

Copy link
Member

@maxlou05 maxlou05 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed

logger/modules/config_logger.yaml Show resolved Hide resolved
assert main_logger is not None

frame = inspect.currentframe()
main_logger.info(f"{MAIN_LOGGER_NAME} logger initialized", frame)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still not want to use the custom name? If so I'd rather just write "main" straight into the string so it's less confusing, because this looks like the default name if the user didn't provide one.

@pytest.fixture
def logger_instance_to_file_enabled() -> logger.Logger: # type: ignore
"""
Returns a logger with logging to file disabled.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in docstring: enabled not disabled?

logger/test_logger.py Show resolved Hide resolved
Comment on lines 15 to 17
def setup_main_logger(
config: "dict", main_logger_name: str = MAIN_LOGGER_NAME
) -> "tuple[bool, logger.Logger | None, pathlib.Path | None]":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we choose to force main logger to log to a file? It should be fine as long as the directory exists, and not the specific main log file?

logger/read_yaml/test_read_yaml.py Show resolved Hide resolved
Comment on lines 120 to 153
def debug(self, message: str, frame: "types.FrameType | None") -> None:
"""
Logs a debug level message.
"""
message = self.message_and_metadata(message, frame)
self.logger.debug(message)

def info(self, message: str, frame: "types.FrameType | None") -> None:
"""
Logs an info level message.
"""
message = self.message_and_metadata(message, frame)
self.logger.info(message)

def warning(self, message: str, frame: "types.FrameType | None") -> None:
"""
Logs a warning level message.
"""
message = self.message_and_metadata(message, frame)
self.logger.warning(message)

def error(self, message: str, frame: "types.FrameType | None") -> None:
"""
Logs an error level message.
"""
message = self.message_and_metadata(message, frame)
self.logger.error(message)

def critical(self, message: str, frame: "types.FrameType | None") -> None:
"""
Logs a critical level message.
"""
message = self.message_and_metadata(message, frame)
self.logger.critical(message)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose that rather than asking the user to pass in a frame, we use inspect in the Logger itself, and we can use frame.f_back to find the caller's frame, which is the one we are interested in. Then we can just have frame be a boolean option that defaults to true, since it seems to be enabled by default on most stack traces and loggers.

Comment on lines 103 to 108
test_message = "test message"
logger_instance_to_file_enabled.debug(test_message, None)
logger_instance_to_file_enabled.info(test_message, None)
logger_instance_to_file_enabled.warning(test_message, None)
logger_instance_to_file_enabled.error(test_message, None)
logger_instance_to_file_enabled.critical(test_message, None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if one had no frame and this one does have frame info

"""
test_message = "test message"

logger_instance_to_file_disabled.debug(test_message, None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for all of these, would be nice to log twice, one with frame and one without

requirements.txt Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also could you please remove line 17-18 (the pymavlink) since it's now moved to the submodule. Thanks!

Copy link
Member

@maxlou05 maxlou05 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed

assert main_logger is not None

frame = inspect.currentframe()
main_logger.info(f"{main_logger_name} logger initialized", frame)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

frame should be true/false, since we changed that.

Comment on lines 126 to 174
def debug(self, message: str, log_with_frame_info: bool) -> None:
"""
Logs a debug level message.
"""
if log_with_frame_info:
logger_frame = inspect.currentframe()
caller_frame = logger_frame.f_back
message = self.message_and_metadata(message, caller_frame)
self.logger.debug(message)

def info(self, message: str, log_with_frame_info: bool) -> None:
"""
Logs an info level message.
"""
if log_with_frame_info:
logger_frame = inspect.currentframe()
caller_frame = logger_frame.f_back
message = self.message_and_metadata(message, caller_frame)
self.logger.info(message)

def warning(self, message: str, log_with_frame_info: bool) -> None:
"""
Logs a warning level message.
"""
if log_with_frame_info:
logger_frame = inspect.currentframe()
caller_frame = logger_frame.f_back
message = self.message_and_metadata(message, caller_frame)
self.logger.warning(message)

def error(self, message: str, log_with_frame_info: bool) -> None:
"""
Logs an error level message.
"""
if log_with_frame_info:
logger_frame = inspect.currentframe()
caller_frame = logger_frame.f_back
message = self.message_and_metadata(message, caller_frame)
self.logger.error(message)

def critical(self, message: str, log_with_frame_info: bool) -> None:
"""
Logs a critical level message.
"""
if log_with_frame_info:
logger_frame = inspect.currentframe()
caller_frame = logger_frame.f_back
message = self.message_and_metadata(message, caller_frame)
self.logger.critical(message)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be nicer to have log_with_frame_info default to True? Up to you tho

logging_path = pathlib.Path(log_directory_path, start_time)

# Create logging directory
pathlib.Path(log_directory_path).mkdir(exist_ok=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*reminder

Copy link
Member

@maxlou05 maxlou05 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved!

@TongguangZhang TongguangZhang merged commit 09811f6 into main Aug 28, 2024
1 check passed
@TongguangZhang TongguangZhang deleted the move_logger_to_common branch August 28, 2024 01:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants