-
Notifications
You must be signed in to change notification settings - Fork 15
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
General comments:
-
Tests for Logger are missing. I think they can be created now.
-
Comment for all classes:
I'm thinking this could actually be part of the object __init__
now, and we can avoid hardcoded strings by using name
, e.g:
class Inspector:
def __init__:
[...]
self.logger = get_logger(actor=Inspector.__name__)
- We may want to change
actor
, since I don't think no-one ever liked that denomination. What aboutmodule
orcomponent
?
common/logger.py
Outdated
Args: | ||
log_name_prefix (:obj:`str`): the prefix of the logger where the data will be stored in (server, client, ...). | ||
actor (:obj:`str`): the system actor that is logging the event (e.g. ``Watcher``, ``Cryptographer``, ...). | ||
Render ``event_dict``. It renders the timestamp, followed by the actor within "[]" (unless it's None), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: event_dict
(missing `` )
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
common/logger.py
Outdated
return msg if self.actor is None else "[{}]: {}".format(self.actor, msg) | ||
def _repr(self, val): | ||
""" | ||
Determine representation of *val* depending on its type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: For docstrings, if it is a one-liner, it should be expressed:
""" <docstring> """ (same line, no full stop)
The return is also missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to a one-line description, and also made the code more compact with a ternary if/else.
common/logger.py
Outdated
log_name_prefix (:obj:`str`): the prefix of the logger where the data will be stored in (server, client, ...). | ||
actor (:obj:`str`): the system actor that is logging the event (e.g. ``Watcher``, ``Cryptographer``, ...). | ||
Render ``event_dict``. It renders the timestamp, followed by the actor within "[]" (unless it's None), | ||
followed by the event, then any remaining item in event_dict in the key=value format |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
docstrings: full-stop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
msg (:obj:`str`): the message to be logged. | ||
kwargs (:obj:`dict`): a ``key:value`` collection parameters to be added to the output. | ||
""" | ||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
docstring: Unnecessary empty line at the end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also some nits: space between parameter and type (param (:obj: ...)
)
No need of parenthesis fort the Return and Raises
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
common/logger.py
Outdated
# force event to str for compatibility with standard library | ||
event = event_dict.pop("event") | ||
if not isinstance(event, str): | ||
event = str(event) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm guessing you're trying to make sure the event (I'd call it msg or message) is a string here. However you'd have the exact same problem that you solved in key_value_part
, if an object with no __str__
method is passed this will fail, so it seems to debunk the purpose of the check.
I'd either use _repr or not have the check + cast at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed using _repr
now.
common/logger.py
Outdated
global configured | ||
|
||
if configured: | ||
raise RuntimeError("logging was already configured.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure this is really necessary.
The point is that this check is that the function should only be called one, isn't it? But this function is supposed to only be called during bootstrap anyway, isn't it?
In any case, this would raise an exception that no-one captures making either cli
or teos
to quit execution.
So, either we do not add this, or we implement is as a singleton?
PS: Given that this has no return, but simply configures logging.config.dictConfig
, you can simply return None if the condition is met, given that it has been already configured.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I think calling this twice means that your code is broken, so it's good if the exception is not handled. Silently failing (and returning None that will likely be ignored) might lead to not detecting that you called it twice - and maybe running with a config you don't expect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I don't think the latter would apply, since the the first time it will configure it with the original conf and the second time will not run it at all, so it would still run with the original conf.
I don't think this is a big deal though, since there is no chance this is called more than once.
If you rather leaving it like this: Cap "Logging" and remove the tailing dot
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, that mean we are choosing the first config, but we don't know which one was the intended one if two are given.
Updated error message in 56adb9b.
def _create_console_message(self, msg, **kwargs): | ||
s_message = _StructuredMessage(self._add_prefix(msg), **kwargs).to_dict() | ||
message = "{} {}".format(s_message["time"], s_message["message"]) | ||
def __call__(self, _, __, event_dict): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
docstrings missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a one-liner docstring, not sure there's more to add as it would repeat the class docstring, basically.
teos/__init__.py
Outdated
@@ -17,6 +16,7 @@ | |||
"BTC_FEED_PROTOCOL": {"value": "tcp", "type": str}, | |||
"BTC_FEED_CONNECT": {"value": "localhost", "type": str}, | |||
"BTC_FEED_PORT": {"value": 28332, "type": int}, | |||
"DAEMON": {"value": 0, "type": int}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can not this be a boolean?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, read comment in teosd.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dropped the two commits adding the daemon config.
teos/teosd.py
Outdated
@@ -53,7 +53,15 @@ def main(command_line_conf): | |||
config["BTC_RPC_PORT"] = get_default_rpc_port(config.get("BTC_NETWORK")) | |||
|
|||
setup_data_folder(data_dir) | |||
setup_logging(config.get("LOG_FILE"), LOG_PREFIX) | |||
|
|||
daemon = config.get("DAEMON") != 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be worth separate this to a different PR to avoid mixing stuff
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dropped the two commits adding the daemon config.
9392c65
to
da4439b
Compare
…now in common.logger); removed LOG_PREFIX; removed Logger class, replaced with a get_logger method with the 'actor' parameter
…rt of a log entry
f3253f5
to
b29eb0d
Compare
Should have addressed almost everything, still a comment suspended about what happens if I added tests for the expected output of CustomLogRenderer in various combinations; not sure what tests to add for setup_logging and get_logger. For get_logger, the problem is also that the object returned is kinda opaque: a test that would make sense is to check whether the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
General comments (there's also some inline):
-
API should have logger as part of the init (using API.name_) instead of globally defined.
-
Cleaner, Responder, and UserDBM can have the name defined using X.name to get rid of a hardcoded value.
-
All the clases that now include logger as part of their attributes are missing the corresponding entry in the docstring. Moreover, entries on args and attributes are sorted by appearance.
-
Needs black formatting (add a file watcher so you can have it applied on every file save).
-
test_logger has a bunch of unused import (install flake8 and use it to check your files).
-
test_logger is only covering CustomLogRenderer
@staticmethod | ||
def _create_file_message(msg, **kwargs): | ||
return json.dumps(_StructuredMessage(msg, **kwargs).to_dict()) | ||
# Represent all the key=value elements still in event_dict |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can surround this by parenthesis so it is easier to parse in case we ever need to:
ts [component] msg (key1=value1, ...)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea, done in e260149.
Should have addressed all the comments. Added the |
By using structlog, it's easier to keep the logs structured and decide how to render them for different purposes.
This PR rewrites the logging module to use structlog, keeping them for now as plaintext, with the following settings:
Also added a "daemon" parameter, that suppresses output to console. It's not a proper daemon support, as the shell is not released; that's not trivial to do and is left for separate work once we figure out the best way to do it.
This should make it relatively easy to integrate any log aggregator, like the kibana dashboard after #148 is merged.