2021-04-19 14:47:30 +02:00
|
|
|
""" Report """
|
|
|
|
|
2021-04-19 14:55:07 +02:00
|
|
|
import atexit
|
2021-04-19 14:47:30 +02:00
|
|
|
import logging
|
|
|
|
|
2023-01-16 12:56:12 +01:00
|
|
|
from mylib.config import ConfigurableObject, StringOption
|
2022-05-27 17:09:51 +02:00
|
|
|
from mylib.email import EmailClient
|
|
|
|
|
2021-05-19 18:07:42 +02:00
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
2021-05-19 19:19:57 +02:00
|
|
|
|
2022-05-27 17:09:51 +02:00
|
|
|
class Report(ConfigurableObject): # pylint: disable=useless-object-inheritance
|
2023-01-16 12:56:12 +01:00
|
|
|
"""Logging report"""
|
2021-04-19 14:47:30 +02:00
|
|
|
|
2023-01-16 12:56:12 +01:00
|
|
|
_config_name = "report"
|
|
|
|
_config_comment = "Email report"
|
2022-05-27 17:09:51 +02:00
|
|
|
_defaults = {
|
2023-01-16 12:56:12 +01:00
|
|
|
"recipient": None,
|
|
|
|
"subject": "Report",
|
|
|
|
"loglevel": "WARNING",
|
|
|
|
"logformat": "%(asctime)s - %(levelname)s - %(message)s",
|
2023-06-19 17:07:59 +02:00
|
|
|
"just_try": False,
|
2022-05-27 17:09:51 +02:00
|
|
|
}
|
|
|
|
|
2021-04-19 14:47:30 +02:00
|
|
|
content = []
|
|
|
|
handler = None
|
|
|
|
formatter = None
|
|
|
|
email_client = None
|
|
|
|
|
2023-12-14 21:41:16 +01:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
email_client=None,
|
|
|
|
add_logging_handler=False,
|
|
|
|
send_at_exit=None,
|
|
|
|
initialize=True,
|
|
|
|
**kwargs,
|
|
|
|
):
|
2022-05-27 17:09:51 +02:00
|
|
|
super().__init__(**kwargs)
|
|
|
|
self.email_client = email_client
|
2023-12-14 21:41:16 +01:00
|
|
|
self.add_logging_handler = add_logging_handler
|
|
|
|
self._send_at_exit = send_at_exit
|
2022-05-27 19:59:47 +02:00
|
|
|
self._attachment_files = []
|
|
|
|
self._attachment_payloads = []
|
2022-05-27 17:09:51 +02:00
|
|
|
|
|
|
|
if initialize:
|
|
|
|
self.initialize()
|
|
|
|
|
|
|
|
def configure(self, **kwargs): # pylint: disable=arguments-differ
|
2023-01-16 12:56:12 +01:00
|
|
|
"""Configure options on registered mylib.Config object"""
|
2023-06-19 17:07:59 +02:00
|
|
|
section = super().configure(
|
|
|
|
just_try_help=kwargs.pop("just_try_help", "Just-try mode: do not really send report"),
|
|
|
|
**kwargs,
|
|
|
|
)
|
2022-05-27 17:09:51 +02:00
|
|
|
|
2023-01-16 12:56:12 +01:00
|
|
|
section.add_option(StringOption, "recipient", comment="Report recipient email address")
|
2022-05-27 17:09:51 +02:00
|
|
|
section.add_option(
|
2023-01-16 12:56:12 +01:00
|
|
|
StringOption,
|
|
|
|
"subject",
|
|
|
|
default=self._defaults["subject"],
|
|
|
|
comment="Report email subject",
|
|
|
|
)
|
2022-05-27 17:09:51 +02:00
|
|
|
section.add_option(
|
2023-01-16 12:56:12 +01:00
|
|
|
StringOption,
|
|
|
|
"loglevel",
|
|
|
|
default=self._defaults["loglevel"],
|
|
|
|
comment='Report log level (as accept by python logging, for instance "INFO")',
|
|
|
|
)
|
2022-05-27 17:09:51 +02:00
|
|
|
section.add_option(
|
2023-01-16 12:56:12 +01:00
|
|
|
StringOption,
|
|
|
|
"logformat",
|
|
|
|
default=self._defaults["logformat"],
|
|
|
|
comment='Report log level (as accept by python logging, for instance "INFO")',
|
|
|
|
)
|
2022-05-27 17:09:51 +02:00
|
|
|
|
|
|
|
if not self.email_client:
|
|
|
|
self.email_client = EmailClient(config=self._config)
|
|
|
|
self.email_client.configure()
|
|
|
|
|
|
|
|
return section
|
|
|
|
|
|
|
|
def initialize(self, loaded_config=None):
|
2023-01-16 12:56:12 +01:00
|
|
|
"""Configuration initialized hook"""
|
2022-05-27 17:09:51 +02:00
|
|
|
super().initialize(loaded_config=loaded_config)
|
2021-04-19 14:47:30 +02:00
|
|
|
self.handler = logging.StreamHandler(self)
|
|
|
|
|
2023-01-16 12:56:12 +01:00
|
|
|
loglevel = self._get_option("loglevel").upper()
|
|
|
|
assert hasattr(logging, loglevel), f"Invalid report loglevel {loglevel}"
|
2022-05-27 17:09:51 +02:00
|
|
|
self.handler.setLevel(getattr(logging, loglevel))
|
|
|
|
|
2023-01-16 12:56:12 +01:00
|
|
|
self.formatter = logging.Formatter(self._get_option("logformat"))
|
2022-05-27 17:09:51 +02:00
|
|
|
self.handler.setFormatter(self.formatter)
|
2021-04-19 14:47:30 +02:00
|
|
|
|
2023-12-14 21:41:16 +01:00
|
|
|
if self.add_logging_handler:
|
|
|
|
logging.getLogger().addHandler(self.handler)
|
|
|
|
if self._send_at_exit:
|
|
|
|
self.send_at_exit()
|
|
|
|
|
2021-04-19 14:47:30 +02:00
|
|
|
def get_handler(self):
|
2024-03-15 09:52:23 +01:00
|
|
|
"""Retrieve logging handler"""
|
2021-04-19 14:47:30 +02:00
|
|
|
return self.handler
|
|
|
|
|
|
|
|
def write(self, msg):
|
2023-01-16 12:56:12 +01:00
|
|
|
"""Write a message"""
|
2021-04-19 14:47:30 +02:00
|
|
|
self.content.append(msg)
|
|
|
|
|
|
|
|
def get_content(self):
|
2023-01-16 12:56:12 +01:00
|
|
|
"""Read the report content"""
|
2021-04-19 14:47:30 +02:00
|
|
|
return "".join(self.content)
|
|
|
|
|
2022-05-27 19:59:47 +02:00
|
|
|
def add_attachment_file(self, filepath):
|
2023-01-16 12:56:12 +01:00
|
|
|
"""Add attachment file"""
|
2022-05-27 19:59:47 +02:00
|
|
|
self._attachment_files.append(filepath)
|
|
|
|
|
|
|
|
def add_attachment_payload(self, payload):
|
2023-01-16 12:56:12 +01:00
|
|
|
"""Add attachment payload"""
|
2022-05-27 19:59:47 +02:00
|
|
|
self._attachment_payloads.append(payload)
|
|
|
|
|
2023-06-19 17:07:59 +02:00
|
|
|
def send(self, subject=None, rcpt_to=None, email_client=None, just_try=None):
|
2023-01-16 12:56:12 +01:00
|
|
|
"""Send report using an EmailClient"""
|
2022-05-27 17:09:51 +02:00
|
|
|
if rcpt_to is None:
|
2023-01-16 12:56:12 +01:00
|
|
|
rcpt_to = self._get_option("recipient")
|
2022-05-27 17:09:51 +02:00
|
|
|
if not rcpt_to:
|
2023-01-16 12:56:12 +01:00
|
|
|
log.debug("No report recipient, do not send report")
|
2021-04-19 14:47:30 +02:00
|
|
|
return True
|
2022-05-27 17:09:51 +02:00
|
|
|
if subject is None:
|
2023-01-16 12:56:12 +01:00
|
|
|
subject = self._get_option("subject")
|
2022-05-27 17:09:51 +02:00
|
|
|
assert subject, "You must provide report subject using Report.__init__ or Report.send"
|
|
|
|
if email_client is None:
|
|
|
|
email_client = self.email_client
|
|
|
|
assert email_client, (
|
2023-01-16 12:56:12 +01:00
|
|
|
"You must provide an email client __init__(), send() or send_at_exit() methods argument"
|
|
|
|
" email_client"
|
|
|
|
)
|
2021-04-19 14:47:30 +02:00
|
|
|
content = self.get_content()
|
2024-05-02 15:56:41 +02:00
|
|
|
if not content and not self._attachment_files and not self._attachment_payloads:
|
2023-01-16 12:56:12 +01:00
|
|
|
log.debug("Report is empty, do not send it")
|
2021-04-19 14:47:30 +02:00
|
|
|
return True
|
2022-05-27 19:59:47 +02:00
|
|
|
msg = email_client.forge_message(
|
2023-01-16 12:56:12 +01:00
|
|
|
rcpt_to,
|
|
|
|
subject=subject,
|
|
|
|
text_body=content,
|
2022-05-27 19:59:47 +02:00
|
|
|
attachment_files=self._attachment_files,
|
2023-01-16 12:56:12 +01:00
|
|
|
attachment_payloads=self._attachment_payloads,
|
|
|
|
)
|
2023-06-19 17:07:59 +02:00
|
|
|
if email_client.send(
|
|
|
|
rcpt_to, msg=msg, just_try=just_try if just_try is not None else self._just_try
|
|
|
|
):
|
2023-01-16 12:56:12 +01:00
|
|
|
log.debug("Report sent to %s", rcpt_to)
|
2021-04-19 14:55:54 +02:00
|
|
|
return True
|
2023-01-16 12:56:12 +01:00
|
|
|
log.error("Fail to send report to %s", rcpt_to)
|
2021-04-19 14:55:54 +02:00
|
|
|
return False
|
2021-04-19 14:55:07 +02:00
|
|
|
|
|
|
|
def send_at_exit(self, **kwargs):
|
2023-01-16 12:56:12 +01:00
|
|
|
"""Send report at exit"""
|
2021-04-19 14:55:07 +02:00
|
|
|
atexit.register(self.send, **kwargs)
|