# SPDX-FileCopyrightText: 2023 Karlsruher Institut für Technologie
#
# SPDX-License-Identifier: CC0-1.0
import logging
# import time
from logging.handlers import HTTPHandler, SMTPHandler, SocketHandler
from typing import Any, Union
from .analysers.properties_verifier import Verifier
[docs]
class IgnoreRepeatedLogFilter(logging.Filter):
def __init__(self):
super().__init__()
self.last_log = []
[docs]
def filter(self, record):
current_msg = record.msg
if current_msg not in self.last_log:
self.last_log.append(current_msg)
return True
return False
[docs]
class Logger:
"""
A class-based logger for TDS2STAC. It supports
all the handlers from the standard python logging
library.
Args:
logger_properties (dict, optional): Logger properties. Defaults to `dict()`.
It's optional and has the following keys:
logger_msg (str, optional)
logger_handler (str, optional)
logger_name (str, optional)
logger_id (str, optional)
logger_level (str, optional)
logger_formatter (str, optional)
logger_handler_host (str, optional)
logger_handler_port (str, optional)
logger_handler_url (str, optional)
logger_handler_method (str, optional)
logger_handler_secure (bool, optional)
logger_handler_credentials (tuple, optional)
logger_handler_context (tuple, optional)
logger_handler_filename (str, optional)
logger_handler_mode (str, optional)
logger_handler_encoding (str, optional)
logger_handler_delay (bool, optional)
logger_handler_errors (str, optional)
logger_handler_mailhost (str, optional)
logger_handler_fromaddr (str, optional)
logger_handler_toaddrs (str, optional)
logger_handler_subject (str, optional)
logger_handler_timeout (str, optional)
"""
logger_properties: Union[dict[str, Any], None]
"""
A dictionary that contains all the logger properties.
It is optional and it is set to `None` by default.
The following keys are supported:
**logger_msg (str, optional):**
Logger message. Defaults to `None`.
But it is required when you want to log a message.
**logger_handler (str, optional):**
Logger handler. Defaults to `NullHandler`.
Check the following website for more information:
https://docs.python.org/3/library/logging.handlers.html#module-logging.handlers
**logger_name (str, optional):**
Logger name. Defaults to `INSUPDEL4STAC`. It's required
when you choose `HTTPHandler` as logger_handler.
**logger_id (str, optional):**
Logger id. Defaults to `1`. It's required when you
choose `HTTPHandler` as logger_handler.
**logger_level (str, optional):**
Logger level. Defaults to `DEBUG`. It's optional.
For more information check the following website:
https://docs.python.org/3/library/logging.html#levels
**logger_formatter (str, optional):**
Logger format. Defaults to `%(levelname)-8s %(asctime)s \\t
%(filename)s @function %(funcName)s line %(lineno)s - %(message)s`.
For more information check the following website:
https://docs.python.org/3/library/logging.html#formatter-objects
**logger_handler_host (str, optional):**
Logger host. Sets the value to 'None' by default.
It is required when `HTTPHandler` or `SocketHandler` are selected as the `logger_handler`.
The `logger_handler` will be set to 'NullHandler' if `HTTPHandler` or `SocketHandler` is
selected as the `logger_handler` value and neither `logger_handler_host` nor
`logger_handler_port` nor are specified.
**logger_handler_port (str, optional):**
Logger port. Sets the value to 'None' by default.
It is required when `HTTPHandler` or `SocketHandler` are selected as the `logger_handler`.
The `logger_handler` will be set to 'NullHandler' if `HTTPHandler` or `SocketHandler` is
selected as the `logger_handler` value and neither `logger_handler_host` nor
`logger_handler_port` are specified.
**logger_handler_url (str, optional):**
Logger url. Sets the value to 'None' by default.
It is required when `HTTPHandler` is selected as the `logger_handler`.
The `logger_handler` will be set to 'NullHandler' if `HTTPHandler` is
selected as the `logger_handler` value and neither `logger_handler_url`
is specified.
**logger_handler_method (str, optional):**
HTTP methods. It supports sending logging messages
to a web server, using either GET or POST semantics. Sets the value to 'None' by default.
It is required when `HTTPHandler` is selected as the `logger_handler`.
The `logger_handler` will be set to 'NullHandler' if `HTTPHandler` is
selected as the `logger_handler` value and `logger_handler_method`
is not specified.
**logger_handler_secure (bool, optional):**
HTTP secure. Sets the value to 'False' by default.
It is utilized when `HTTPHandler` or `SMTPHandler` are selected as the `logger_handler`.
But it is optional in both logger handlers.
**logger_handler_credentials (tuple, optional):**
HTTP credentials. Sets the value to 'None' by default.
It is utilized when `HTTPHandler` or `SMTPHandler` are selected as the `logger_handler`.
But it is optional in both logger handlers.
**logger_handler_context (tuple, optional):**
HTTP context. Sets the value to 'None' by default.
It is utilized when `HTTPHandler` is selected as the `logger_handler`.
But it is optional in both logger handlers.
**logger_handler_filename (str, optional):**
File name. Sets the value to 'None' by default.
It is required when `FileHandler` or `WatchedFileHandler` are selected as the `logger_handler`.
The `logger_handler` will be set to 'NullHandler' if `FileHandler` or `WatchedFileHandler` is
selected as the `logger_handler` value and `logger_handler_filename` is not specified.
**logger_handler_mode (str, optional):**
File mode. Sets the value to 'None' by default.
It is required when `FileHandler` or `WatchedFileHandler` are selected as the `logger_handler`.
The `logger_handler` will be set to 'NullHandler' if `FileHandler` or `WatchedFileHandler` is
selected as the `logger_handler` value and `logger_handler_mode` is not specified.
**logger_handler_encoding (str, optional):**
File encoding. Sets the value to 'None' by default.
It is utilized when `FileHandler` or `WatchedFileHandler` are selected as the `logger_handler`.
But it is optional in both logger handlers.
**logger_handler_delay (bool, optional):**
File delay. Sets the value to 'False' by default.
It is utilized when `FileHandler` or `WatchedFileHandler` are selected as the `logger_handler`.
But it is optional in both logger handlers.
**logger_handler_errors (str, optional):**
File errors. Sets the value to 'None' by default.
It is utilized when `FileHandler` or `WatchedFileHandler` are selected as the `logger_handler`.
But it is optional in both logger handlers.
**logger_handler_mailhost (str, optional):**
Mail host. Sets the value to 'None' by default.
It is required when `SMTPHandler` is selected as the `logger_handler`.
The `logger_handler` will be set to 'NullHandler' if `SMTPHandler` is
selected as the `logger_handler` value and `logger_handler_mailhost` is not specified.
**logger_handler_fromaddr (str, optional):**
Mail from address. Sets the value to 'None' by default.
It is required when `SMTPHandler` is selected as the `logger_handler`.
The `logger_handler` will be set to 'NullHandler' if `SMTPHandler` is
selected as the `logger_handler` value and `logger_handler_fromaddr` is not specified.
**logger_handler_toaddrs (str, optional):**
Mail to address. Sets the value to 'None' by default.
It is required when `SMTPHandler` is selected as the `logger_handler`.
The `logger_handler` will be set to 'NullHandler' if `SMTPHandler` is
selected as the `logger_handler` value and `logger_handler_toaddrs` is not specified.
**logger_handler_subject (str, optional):**
Mail subject. Sets the value to 'None' by default.
It is utilized when `SMTPHandler` is selected as the `logger_handler`.
But it is optional in both logger handlers.
**logger_handler_timeout (str, optional):**
Mail timeout. Sets the value to 'None' by default.
It is utilized when `SMTPHandler` is selected as the `logger_handler`.
But it is optional in both logger handlers.
"""
def __init__(
self,
logger_properties: Union[dict[str, Any], None] = dict(),
):
##############################################
# Setting the logger properties
##############################################
verifier = Verifier()
if logger_properties is not None and isinstance(
logger_properties, dict
):
verifier.logger_properties(logger_properties)
###############################################
# Choosing the logger name and ID if they are
# not set when the HTTPHandler is selected as
# the logger handler
###############################################
if logger_properties.get("logger_name") is None:
logger_properties["logger_name"] = "INSUPDEL4STAC"
if logger_properties.get("logger_id") is None:
logger_properties["logger_id"] = "1"
###############################################
# Specifying the standard logger parameters for
# all handlers
###############################################
self.logger = logging.getLogger(
str(logger_properties["logger_name"])
+ "_"
+ str(logger_properties["logger_id"])
)
if logger_properties.get("logger_level") is None:
self.logger.setLevel(level=logging.DEBUG)
logger_properties["logger_level"] = "DEBUG"
elif logger_properties.get(
"logger_level"
) is not None and logger_properties.get("logger_level") in [
"NOTSET",
"DEBUG",
"INFO",
"WARNING",
"ERROR",
"CRITICAL",
]:
self.logger.setLevel(level=logger_properties["logger_level"])
if logger_properties.get("logger_formatter") is None:
logFormatter = logging.Formatter(
fmt="%(levelname)-8s %(asctime)s \t %(filename)s @function %(funcName)s line %(lineno)s - %(message)s",
)
elif logger_properties.get("logger_formatter") is not None:
logFormatter = logging.Formatter(
fmt=logger_properties["logger_formatter"],
)
###############################################
# Verifying that the logger handler is supported
# by the current version of INSUPDEL4STAC
###############################################
if logger_properties.get(
"logger_handler"
) is not None and logger_properties.get("logger_handler") not in [
"NullHandler",
"StreamHandler",
"HTTPHandler",
"FileHandler",
"WatchedFileHandler",
"SocketHandler",
"SMTPHandler",
]:
print(
"Warning: The current version of INSUPDEL4STAC is incompatible with your Logging Handler. It will be set automatically to `NullHandler`"
)
self.Null_Handler()
return
###############################################
# Self.legger is defining here depending on the
# `logger_handler`
###############################################
if (
logger_properties.get("logger_handler") is None
or logger_properties.get("logger_handler") == "NullHandler"
):
self.Null_Handler()
elif logger_properties.get("logger_handler") == "StreamHandler":
streamHandler = logging.StreamHandler()
streamHandler.setFormatter(logFormatter)
streamHandler.setLevel(logging.DEBUG)
# Create the filter and add it to the handler
ignore_repeated_filter = IgnoreRepeatedLogFilter()
streamHandler.addFilter(ignore_repeated_filter)
if self.logger.handlers == [] or not any(
"StreamHandler"
in self.logger.handlers[i].__class__.__name__
for i in range(len(self.logger.handlers))
):
self.logger.addHandler(streamHandler)
elif logger_properties.get("logger_handler") == "SocketHandler":
if (
logger_properties.get("logger_handler_host") is None
or logger_properties.get("logger_handler_port") is None
):
print(
"Warning: You must specify `logger_handler_host` and `logger_handler_port` \
when selecting `SocketHandler` as the `logger_handler`. if not, `logger_handler` \
will transition to `NullHandler`"
)
self.Null_Handler()
return
socketHandler = SocketHandler( # type: ignore
host=str(logger_properties.get("logger_handler_host")),
port=(logger_properties.get("logger_handler_port")),
)
socketHandler.setFormatter(logFormatter)
socketHandler.setLevel(logging.DEBUG)
ignore_repeated_filter = IgnoreRepeatedLogFilter()
socketHandler.addFilter(ignore_repeated_filter)
if self.logger.handlers == [] or not any(
"SocketHandler"
in self.logger.handlers[i].__class__.__name__
for i in range(len(self.logger.handlers))
):
self.logger.addHandler(socketHandler)
elif logger_properties.get("logger_handler") == "HTTPHandler":
if (
logger_properties.get("logger_handler_host") is None
or logger_properties.get("logger_handler_port") is None
or logger_properties.get("logger_handler_url") is None
or logger_properties.get("logger_handler_method") is None
):
print(
"Warning: You must specify `logger_handler_host`, `logger_handler_port`, \
`logger_handler_url`, `logger_handler_method` when selecting `HTTPHandler` \
as the `logger_handler`. if not, `logger_handler` will transition to `NullHandler`"
)
self.Null_Handler()
return
httpHandler = HTTPHandler( # type: ignore
host=str(logger_properties.get("logger_handler_host"))
+ ":"
+ str(logger_properties.get("logger_handler_port")),
url=str(logger_properties.get("logger_handler_url")),
method=str(logger_properties.get("logger_handler_method")),
secure=bool(
logger_properties.get("logger_handler_secure")
),
credentials=logger_properties.get(
"logger_handler_credentials"
),
context=logger_properties.get("logger_handler_context"),
)
httpHandler.setFormatter(logFormatter)
httpHandler.setLevel(logging.DEBUG)
ignore_repeated_filter = IgnoreRepeatedLogFilter()
httpHandler.addFilter(ignore_repeated_filter)
if self.logger.handlers == [] or not any(
"HTTPHandler" in self.logger.handlers[i].__class__.__name__
for i in range(len(self.logger.handlers))
):
self.logger.addHandler(httpHandler)
elif logger_properties.get("logger_handler") == "FileHandler":
if (
logger_properties.get("logger_handler_filename") is None
or logger_properties.get("logger_handler_mode") is None
):
print(
"Warning: You must specify `logger_handler_filename` and `logger_handler_mode` \
when selecting `FileHandler` as the `logger_handler`. if not, `logger_handler`\
will transition to `NullHandler`"
)
self.Null_Handler()
return
fileHandler = logging.FileHandler(
filename=str(
logger_properties.get("logger_handler_filename")
),
mode=str(logger_properties.get("logger_handler_mode")),
encoding=logger_properties.get("logger_handler_encoding"),
delay=bool(logger_properties.get("logger_handler_delay")),
errors=logger_properties.get("logger_handler_errors"),
)
fileHandler.setFormatter(logFormatter)
fileHandler.setLevel(logging.DEBUG)
ignore_repeated_filter = IgnoreRepeatedLogFilter()
fileHandler.addFilter(ignore_repeated_filter)
if self.logger.handlers == [] or not any(
"FileHandler" in self.logger.handlers[i].__class__.__name__
for i in range(len(self.logger.handlers))
):
self.logger.addHandler(fileHandler)
elif logger_properties.get("logger_handler") == "SMTPHandler":
if (
logger_properties.get("logger_handler_mailhost") is None
or logger_properties.get("logger_handler_fromaddr") is None
or logger_properties.get("logger_handler_toaddrs") is None
or logger_properties.get("logger_handler_subject") is None
):
print(
"Warning: You must specify `logger_handler_mailhost`, `logger_handler_fromaddr`, \
`logger_handler_toaddrs`, `logger_handler_subject` when selecting `SMTPHandler` \
as the `logger_handler`. if not, `logger_handler` will transition to `NullHandler`"
)
self.Null_Handler()
return
smtpHandler = SMTPHandler( # type: ignore
mailhost=str(
logger_properties.get("logger_handler_mailhost")
),
fromaddr=str(
logger_properties.get("logger_handler_fromaddr")
),
toaddrs=str(
logger_properties.get("logger_handler_toaddrs")
),
subject=str(
logger_properties.get("logger_handler_subject")
),
credentials=logger_properties.get(
"logger_handler_credentials"
),
secure=logger_properties.get("logger_handler_secure"),
timeout=float(
str(logger_properties.get("logger_handler_timeout"))
),
)
smtpHandler.setFormatter(logFormatter)
smtpHandler.setLevel(logging.DEBUG)
ignore_repeated_filter = IgnoreRepeatedLogFilter()
smtpHandler.addFilter(ignore_repeated_filter)
if self.logger.handlers == [] or not any(
"SMTPHandler" in self.logger.handlers[i].__class__.__name__
for i in range(len(self.logger.handlers))
):
self.logger.addHandler(smtpHandler)
if logger_properties.get("logger_msg") is not None:
if logger_properties.get("logger_level") is not None and (
logger_properties.get("logger_level") == "DEBUG"
or logger_properties.get("logger_level") == "NOTSET"
):
self.logger.debug(logger_properties.get("logger_msg"))
elif (
logger_properties.get("logger_level") is not None
and logger_properties.get("logger_level") == "INFO"
):
self.logger.info(logger_properties.get("logger_msg"))
elif (
logger_properties.get("logger_level") is not None
and logger_properties.get("logger_level") == "WARNING"
):
self.logger.warning(logger_properties.get("logger_msg"))
elif (
logger_properties.get("logger_level") is not None
and logger_properties.get("logger_level") == "ERROR"
):
self.logger.error(logger_properties.get("logger_msg"))
elif (
logger_properties.get("logger_level") is not None
and logger_properties.get("logger_level") == "CRITICAL"
):
self.logger.critical(logger_properties.get("logger_msg"))
[docs]
def Null_Handler(self):
"""
This is a function to return a NullHandler
"""
nullhandler = logging.NullHandler()
self.logger.handlers = []
self.logger.addHandler(nullhandler)