Fix end-to-end tests and update more log messages (#635).

This commit is contained in:
Dan Helfman
2025-01-26 19:03:40 -08:00
parent 7d56641f56
commit 31b6e21139
18 changed files with 108 additions and 88 deletions
+5
View File
@@ -108,6 +108,7 @@ def run_configuration(config_filename, config, config_paths, arguments):
'initialize_monitor',
config,
dispatch.Hook_type.MONITORING,
config_filename,
monitoring_log_level,
global_arguments.dry_run,
)
@@ -116,6 +117,7 @@ def run_configuration(config_filename, config, config_paths, arguments):
'ping_monitor',
config,
dispatch.Hook_type.MONITORING,
config_filename,
monitor.State.START,
monitoring_log_level,
global_arguments.dry_run,
@@ -187,6 +189,7 @@ def run_configuration(config_filename, config, config_paths, arguments):
'ping_monitor',
config,
dispatch.Hook_type.MONITORING,
config_filename,
monitor.State.LOG,
monitoring_log_level,
global_arguments.dry_run,
@@ -203,6 +206,7 @@ def run_configuration(config_filename, config, config_paths, arguments):
'ping_monitor',
config,
dispatch.Hook_type.MONITORING,
config_filename,
monitor.State.FINISH,
monitoring_log_level,
global_arguments.dry_run,
@@ -237,6 +241,7 @@ def run_configuration(config_filename, config, config_paths, arguments):
'ping_monitor',
config,
dispatch.Hook_type.MONITORING,
config_filename,
monitor.State.FAIL,
monitoring_log_level,
global_arguments.dry_run,
+4 -4
View File
@@ -66,12 +66,12 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
)
if not hook_config.get('services'):
logger.info(f'{config_filename}: No Apprise services to ping')
logger.info('No Apprise services to ping')
return
dry_run_string = ' (dry run; not actually pinging)' if dry_run else ''
labels_string = ', '.join(map(operator.itemgetter('label'), hook_config.get('services')))
logger.info(f'{config_filename}: Pinging Apprise services: {labels_string}{dry_run_string}')
logger.info(f'Pinging Apprise services: {labels_string}{dry_run_string}')
apprise_object = apprise.Apprise()
apprise_object.add(list(map(operator.itemgetter('url'), hook_config.get('services'))))
@@ -100,10 +100,10 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
)
if result is False:
logger.warning(f'{config_filename}: Error sending some Apprise notifications')
logger.warning('Error sending some Apprise notifications')
def destroy_monitor(hook_config, config, config_filename, monitoring_log_level, dry_run):
def destroy_monitor(hook_config, config, monitoring_log_level, dry_run):
'''
Remove the monitor handler that was added to the root logger. This prevents the handler from
getting reused by other instances of this monitor.
+5 -5
View File
@@ -29,7 +29,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
'''
if state not in MONITOR_STATE_TO_CRONHUB:
logger.debug(
f'{config_filename}: Ignoring unsupported monitoring {state.name.lower()} in Cronhub hook'
f'Ignoring unsupported monitoring {state.name.lower()} in Cronhub hook'
)
return
@@ -41,8 +41,8 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
.replace('/ping/', formatted_state)
)
logger.info(f'{config_filename}: Pinging Cronhub {state.name.lower()}{dry_run_label}')
logger.debug(f'{config_filename}: Using Cronhub ping URL {ping_url}')
logger.info(f'Pinging Cronhub {state.name.lower()}{dry_run_label}')
logger.debug(f'Using Cronhub ping URL {ping_url}')
if not dry_run:
logging.getLogger('urllib3').setLevel(logging.ERROR)
@@ -51,11 +51,11 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
if not response.ok:
response.raise_for_status()
except requests.exceptions.RequestException as error:
logger.warning(f'{config_filename}: Cronhub error: {error}')
logger.warning(f'Cronhub error: {error}')
def destroy_monitor(
ping_url_or_uuid, config, config_filename, monitoring_log_level, dry_run
ping_url_or_uuid, config, monitoring_log_level, dry_run
): # pragma: no cover
'''
No destruction is necessary for this monitor.
+5 -5
View File
@@ -29,15 +29,15 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
'''
if state not in MONITOR_STATE_TO_CRONITOR:
logger.debug(
f'{config_filename}: Ignoring unsupported monitoring {state.name.lower()} in Cronitor hook'
f'Ignoring unsupported monitoring {state.name.lower()} in Cronitor hook'
)
return
dry_run_label = ' (dry run; not actually pinging)' if dry_run else ''
ping_url = f"{hook_config['ping_url']}/{MONITOR_STATE_TO_CRONITOR[state]}"
logger.info(f'{config_filename}: Pinging Cronitor {state.name.lower()}{dry_run_label}')
logger.debug(f'{config_filename}: Using Cronitor ping URL {ping_url}')
logger.info(f'Pinging Cronitor {state.name.lower()}{dry_run_label}')
logger.debug(f'Using Cronitor ping URL {ping_url}')
if not dry_run:
logging.getLogger('urllib3').setLevel(logging.ERROR)
@@ -46,11 +46,11 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
if not response.ok:
response.raise_for_status()
except requests.exceptions.RequestException as error:
logger.warning(f'{config_filename}: Cronitor error: {error}')
logger.warning(f'Cronitor error: {error}')
def destroy_monitor(
ping_url_or_uuid, config, config_filename, monitoring_log_level, dry_run
ping_url_or_uuid, config, monitoring_log_level, dry_run
): # pragma: no cover
'''
No destruction is necessary for this monitor.
+6 -6
View File
@@ -56,7 +56,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
if 'states' in hook_config and state.name.lower() not in hook_config['states']:
logger.info(
f'{config_filename}: Skipping Healthchecks {state.name.lower()} ping due to configured states'
f'Skipping Healthchecks {state.name.lower()} ping due to configured states'
)
return
@@ -69,13 +69,13 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
if hook_config.get('create_slug'):
if ping_url_is_uuid:
logger.warning(
f'{config_filename}: Healthchecks UUIDs do not support auto provisionning; ignoring'
'Healthchecks UUIDs do not support auto provisionning; ignoring'
)
else:
ping_url = f'{ping_url}?create=1'
logger.info(f'{config_filename}: Pinging Healthchecks {state.name.lower()}{dry_run_label}')
logger.debug(f'{config_filename}: Using Healthchecks ping URL {ping_url}')
logger.info(f'Pinging Healthchecks {state.name.lower()}{dry_run_label}')
logger.debug(f'Using Healthchecks ping URL {ping_url}')
if state in (monitor.State.FINISH, monitor.State.FAIL, monitor.State.LOG):
payload = borgmatic.hooks.monitoring.logs.format_buffered_logs_for_payload(
@@ -93,10 +93,10 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
if not response.ok:
response.raise_for_status()
except requests.exceptions.RequestException as error:
logger.warning(f'{config_filename}: Healthchecks error: {error}')
logger.warning(f'Healthchecks error: {error}')
def destroy_monitor(hook_config, config, config_filename, monitoring_log_level, dry_run):
def destroy_monitor(hook_config, config, monitoring_log_level, dry_run):
'''
Remove the monitor handler that was added to the root logger. This prevents the handler from
getting reused by other instances of this monitor.
+2 -2
View File
@@ -139,10 +139,10 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
for handler in tuple(logging.getLogger().handlers):
if isinstance(handler, Loki_log_handler):
if state in MONITOR_STATE_TO_LOKI.keys():
handler.raw(f'{config_filename}: {MONITOR_STATE_TO_LOKI[state]} backup')
handler.raw(f'{MONITOR_STATE_TO_LOKI[state]} backup')
def destroy_monitor(hook_config, config, config_filename, monitoring_log_level, dry_run):
def destroy_monitor(hook_config, config, monitoring_log_level, dry_run):
'''
Remove the monitor handler that was added to the root logger.
'''
+8 -8
View File
@@ -37,8 +37,8 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
base_url = hook_config.get('server', 'https://ntfy.sh')
topic = hook_config.get('topic')
logger.info(f'{config_filename}: Pinging ntfy topic {topic}{dry_run_label}')
logger.debug(f'{config_filename}: Using Ntfy ping URL {base_url}/{topic}')
logger.info(f'Pinging ntfy topic {topic}{dry_run_label}')
logger.debug(f'Using Ntfy ping URL {base_url}/{topic}')
headers = {
'X-Title': state_config.get('title'),
@@ -55,19 +55,19 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
if access_token is not None:
if username or password:
logger.warning(
f'{config_filename}: ntfy access_token is set but so is username/password, only using access_token'
'ntfy access_token is set but so is username/password, only using access_token'
)
auth = requests.auth.HTTPBasicAuth('', access_token)
elif (username and password) is not None:
auth = requests.auth.HTTPBasicAuth(username, password)
logger.info(f'{config_filename}: Using basic auth with user {username} for ntfy')
logger.info(f'Using basic auth with user {username} for ntfy')
elif username is not None:
logger.warning(
f'{config_filename}: Password missing for ntfy authentication, defaulting to no auth'
'Password missing for ntfy authentication, defaulting to no auth'
)
elif password is not None:
logger.warning(
f'{config_filename}: Username missing for ntfy authentication, defaulting to no auth'
'Username missing for ntfy authentication, defaulting to no auth'
)
if not dry_run:
@@ -77,11 +77,11 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
if not response.ok:
response.raise_for_status()
except requests.exceptions.RequestException as error:
logger.warning(f'{config_filename}: ntfy error: {error}')
logger.warning(f'ntfy error: {error}')
def destroy_monitor(
ping_url_or_uuid, config, config_filename, monitoring_log_level, dry_run
ping_url_or_uuid, config, monitoring_log_level, dry_run
): # pragma: no cover
'''
No destruction is necessary for this monitor.
+5 -5
View File
@@ -29,12 +29,12 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
'''
if state != monitor.State.FAIL:
logger.debug(
f'{config_filename}: Ignoring unsupported monitoring {state.name.lower()} in PagerDuty hook',
f'Ignoring unsupported monitoring {state.name.lower()} in PagerDuty hook',
)
return
dry_run_label = ' (dry run; not actually sending)' if dry_run else ''
logger.info(f'{config_filename}: Sending failure event to PagerDuty {dry_run_label}')
logger.info(f'Sending failure event to PagerDuty {dry_run_label}')
if dry_run:
return
@@ -61,7 +61,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
},
}
)
logger.debug(f'{config_filename}: Using PagerDuty payload: {payload}')
logger.debug(f'Using PagerDuty payload: {payload}')
logging.getLogger('urllib3').setLevel(logging.ERROR)
try:
@@ -69,11 +69,11 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
if not response.ok:
response.raise_for_status()
except requests.exceptions.RequestException as error:
logger.warning(f'{config_filename}: PagerDuty error: {error}')
logger.warning(f'PagerDuty error: {error}')
def destroy_monitor(
ping_url_or_uuid, config, config_filename, monitoring_log_level, dry_run
ping_url_or_uuid, config, monitoring_log_level, dry_run
): # pragma: no cover
'''
No destruction is necessary for this monitor.
+5 -5
View File
@@ -35,14 +35,14 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
token = hook_config.get('token')
user = hook_config.get('user')
logger.info(f'{config_filename}: Updating Pushover{dry_run_label}')
logger.info(f'Updating Pushover{dry_run_label}')
if state_config.get('priority') == EMERGENCY_PRIORITY:
if 'expire' not in state_config:
logger.info(f'{config_filename}: Setting expire to default (10 min).')
logger.info('Setting expire to default (10 min)')
state_config['expire'] = 600
if 'retry' not in state_config:
logger.info(f'{config_filename}: Setting retry to default (30 sec).')
logger.info('Setting retry to default (30 sec)')
state_config['retry'] = 30
else:
if 'expire' in state_config or 'retry' in state_config:
@@ -75,11 +75,11 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
if not response.ok:
response.raise_for_status()
except requests.exceptions.RequestException as error:
logger.warning(f'{config_filename}: Pushover error: {error}')
logger.warning(f'Pushover error: {error}')
def destroy_monitor(
ping_url_or_uuid, config, config_filename, monitoring_log_level, dry_run
ping_url_or_uuid, config, monitoring_log_level, dry_run
): # pragma: no cover
'''
No destruction is necessary for this monitor.
+7 -7
View File
@@ -16,7 +16,7 @@ def initialize_monitor(
DATA_SOURCE_NAME_URL_PATTERN = re.compile(
'^(?P<protocol>.*)://(?P<username>.*)@(?P<hostname>.*)/(?P<project_id>.*)$'
'^(?P<protocol>.+)://(?P<username>.+)@(?P<hostname>.+)/(?P<project_id>.+)$'
)
@@ -39,14 +39,14 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
if not match:
logger.warning(
'f{config_filename}: Invalid Sentry data source name URL: {data_source_name_url}'
f'Invalid Sentry data source name URL: {data_source_name_url}'
)
return
cron_url = f'{match.group("protocol")}://{match.group("hostname")}/api/{match.group("project_id")}/cron/{monitor_slug}/{match.group("username")}/'
logger.info(f'{config_filename}: Pinging Sentry {state.name.lower()}{dry_run_label}')
logger.debug(f'{config_filename}: Using Sentry cron URL {cron_url}')
logger.info(f'Pinging Sentry {state.name.lower()}{dry_run_label}')
logger.debug(f'Using Sentry cron URL {cron_url}')
status = {
'start': 'in_progress',
@@ -55,7 +55,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
}.get(state.name.lower())
if not status:
logger.warning('f{config_filename}: Invalid Sentry state')
logger.warning('Invalid Sentry state')
return
if dry_run:
@@ -67,11 +67,11 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
if not response.ok:
response.raise_for_status()
except requests.exceptions.RequestException as error:
logger.warning(f'{config_filename}: Sentry error: {error}')
logger.warning(f'Sentry error: {error}')
def destroy_monitor(
ping_url_or_uuid, config, config_filename, monitoring_log_level, dry_run
ping_url_or_uuid, config, monitoring_log_level, dry_run
): # pragma: no cover
'''
No destruction is necessary for this monitor.
+4 -4
View File
@@ -29,9 +29,9 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
push_url = hook_config.get('push_url', 'https://example.uptime.kuma/api/push/abcd1234')
query = f'status={status}&msg={state.name.lower()}'
logger.info(
f'{config_filename}: Pushing Uptime Kuma push_url {push_url}?{query} {dry_run_label}'
f'Pushing Uptime Kuma push_url {push_url}?{query} {dry_run_label}'
)
logger.debug(f'{config_filename}: Full Uptime Kuma state URL {push_url}?{query}')
logger.debug(f'Full Uptime Kuma state URL {push_url}?{query}')
if dry_run:
return
@@ -43,11 +43,11 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
if not response.ok:
response.raise_for_status()
except requests.exceptions.RequestException as error:
logger.warning(f'{config_filename}: Uptime Kuma error: {error}')
logger.warning(f'Uptime Kuma error: {error}')
def destroy_monitor(
push_url_or_uuid, config, config_filename, monitoring_log_level, dry_run
push_url_or_uuid, config, monitoring_log_level, dry_run
): # pragma: no cover
'''
No destruction is necessary for this monitor.
+16 -16
View File
@@ -44,16 +44,16 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
value = state_config.get('value')
headers = {'Content-Type': 'application/json-rpc'}
logger.info(f'{config_filename}: Updating Zabbix{dry_run_label}')
logger.debug(f'{config_filename}: Using Zabbix URL: {server}')
logger.info(f'Updating Zabbix{dry_run_label}')
logger.debug(f'Using Zabbix URL: {server}')
if server is None:
logger.warning(f'{config_filename}: Server missing for Zabbix')
logger.warning('Server missing for Zabbix')
return
# Determine the Zabbix method used to store the value: itemid or host/key
if itemid is not None:
logger.info(f'{config_filename}: Updating {itemid} on Zabbix')
logger.info(f'Updating {itemid} on Zabbix')
data = {
'jsonrpc': '2.0',
'method': 'history.push',
@@ -62,7 +62,7 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
}
elif (host and key) is not None:
logger.info(f'{config_filename}: Updating Host:{host} and Key:{key} on Zabbix')
logger.info(f'Updating Host:{host} and Key:{key} on Zabbix')
data = {
'jsonrpc': '2.0',
'method': 'history.push',
@@ -71,23 +71,23 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
}
elif host is not None:
logger.warning(f'{config_filename}: Key missing for Zabbix')
logger.warning('Key missing for Zabbix')
return
elif key is not None:
logger.warning(f'{config_filename}: Host missing for Zabbix.')
logger.warning('Host missing for Zabbix')
return
else:
logger.warning(f'{config_filename}: No zabbix itemid or host/key provided.')
logger.warning('No Zabbix itemid or host/key provided')
return
# Determine the authentication method: API key or username/password
if api_key is not None:
logger.info(f'{config_filename}: Using API key auth for Zabbix')
logger.info('Using API key auth for Zabbix')
headers['Authorization'] = 'Bearer ' + api_key
elif (username and password) is not None:
logger.info(f'{config_filename}: Using user/pass auth with user {username} for Zabbix')
logger.info('Using user/pass auth with user {username} for Zabbix')
auth_data = {
'jsonrpc': '2.0',
'method': 'user.login',
@@ -102,18 +102,18 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
if not response.ok:
response.raise_for_status()
except requests.exceptions.RequestException as error:
logger.warning(f'{config_filename}: Zabbix error: {error}')
logger.warning(f'Zabbix error: {error}')
return
elif username is not None:
logger.warning(f'{config_filename}: Password missing for Zabbix authentication')
logger.warning('Password missing for Zabbix authentication')
return
elif password is not None:
logger.warning(f'{config_filename}: Username missing for Zabbix authentication')
logger.warning('Username missing for Zabbix authentication')
return
else:
logger.warning(f'{config_filename}: Authentication data missing for Zabbix')
logger.warning('Authentication data missing for Zabbix')
return
if not dry_run:
@@ -123,11 +123,11 @@ def ping_monitor(hook_config, config, config_filename, state, monitoring_log_lev
if not response.ok:
response.raise_for_status()
except requests.exceptions.RequestException as error:
logger.warning(f'{config_filename}: Zabbix error: {error}')
logger.warning(f'Zabbix error: {error}')
def destroy_monitor(
ping_url_or_uuid, config, config_filename, monitoring_log_level, dry_run
ping_url_or_uuid, config, monitoring_log_level, dry_run
): # pragma: no cover
'''
No destruction is necessary for this monitor.
+28 -12
View File
@@ -186,6 +186,31 @@ def add_custom_log_levels(): # pragma: no cover
add_logging_level('DISABLED', DISABLED)
def get_log_prefix():
'''
Return the current log prefix from the defaults for the formatter on the first logging handler.
'''
try:
return next(
handler.formatter._style._defaults.get('prefix').rstrip().rstrip(':')
for handler in logging.getLogger().handlers
)
except (StopIteration, AttributeError):
return None
def set_log_prefix(prefix):
'''
Given a log prefix as a string, set it into the defaults for the formatters on all logging
handlers.
'''
for handler in logging.getLogger().handlers:
try:
handler.formatter._style._defaults = {'prefix': f'{prefix}: ' if prefix else ''}
except AttributeError:
pass
class Log_prefix:
'''
A Python context manager for setting a log prefix so that it shows up in every subsequent
@@ -215,23 +240,14 @@ class Log_prefix:
up in every log message. But first, save off any original prefix so that it can be restored
below.
'''
try:
self.original_prefix = next(
handler.formatter._style._defaults.get('prefix').rstrip().rstrip(':')
for handler in logging.getLogger().handlers
)
except (StopIteration, AttributeError):
self.original_prefix = None
for handler in logging.getLogger().handlers:
handler.formatter._style._defaults = {'prefix': f'{self.prefix}: ' if self.prefix else ''}
self.original_prefix = get_log_prefix()
set_log_prefix(self.prefix)
def __exit__(self, exception, value, traceback):
'''
Restore any original prefix.
'''
for handler in logging.getLogger().handlers:
handler.formatter._style._defaults = {'prefix': f'{self.original_prefix}: ' if self.original_prefix else ''}
set_log_prefix(self.original_prefix)
def configure_logging(
+1 -1
View File
@@ -28,7 +28,7 @@ def generate_configuration(config_path, repository_path):
config_file.close()
def test_override_get_normalized():
def test_override_gets_normalized():
temporary_directory = tempfile.mkdtemp()
repository_path = os.path.join(temporary_directory, 'test.borg')
@@ -14,7 +14,7 @@ def test_destroy_monitor_removes_apprise_handler():
)
)
module.destroy_monitor(flexmock(), flexmock(), flexmock(), flexmock(), flexmock())
module.destroy_monitor(flexmock(), flexmock(), flexmock(), flexmock())
assert logger.handlers == original_handlers
@@ -23,6 +23,6 @@ def test_destroy_monitor_without_apprise_handler_does_not_raise():
logger = logging.getLogger()
original_handlers = list(logger.handlers)
module.destroy_monitor(flexmock(), flexmock(), flexmock(), flexmock(), flexmock())
module.destroy_monitor(flexmock(), flexmock(), flexmock(), flexmock())
assert logger.handlers == original_handlers
@@ -14,7 +14,7 @@ def test_destroy_monitor_removes_healthchecks_handler():
)
)
module.destroy_monitor(flexmock(), flexmock(), flexmock(), flexmock(), flexmock())
module.destroy_monitor(flexmock(), flexmock(), flexmock(), flexmock())
assert logger.handlers == original_handlers
@@ -23,6 +23,6 @@ def test_destroy_monitor_without_healthchecks_handler_does_not_raise():
logger = logging.getLogger()
original_handlers = list(logger.handlers)
module.destroy_monitor(flexmock(), flexmock(), flexmock(), flexmock(), flexmock())
module.destroy_monitor(flexmock(), flexmock(), flexmock(), flexmock())
assert logger.handlers == original_handlers
@@ -65,8 +65,8 @@ def test_ping_monitor_adds_log_message():
assert any(
map(
lambda log: log
== f'{config_filename}: {module.MONITOR_STATE_TO_LOKI[module.monitor.State.FINISH]} backup',
map(lambda x: x[1], handler.buffer.root['streams'][0]['values']),
== f'{module.MONITOR_STATE_TO_LOKI[module.monitor.State.FINISH]} backup',
map(lambda value: value[1], handler.buffer.root['streams'][0]['values']),
)
)
return
@@ -82,7 +82,7 @@ def test_destroy_monitor_removes_log_handler():
config_filename = 'test.yaml'
dry_run = True
module.initialize_monitor(hook_config, flexmock(), config_filename, flexmock(), dry_run)
module.destroy_monitor(hook_config, flexmock(), config_filename, flexmock(), dry_run)
module.destroy_monitor(hook_config, flexmock(), flexmock(), dry_run)
for handler in tuple(logging.getLogger().handlers):
if isinstance(handler, module.Loki_log_handler):
@@ -379,7 +379,6 @@ def test_destroy_monitor_does_not_raise():
module.destroy_monitor(
hook_config={},
config={},
config_filename='test.yaml',
monitoring_log_level=1,
dry_run=False,
)