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

Add logger in fixity script #49

Merged
merged 5 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 53 additions & 27 deletions fixity/fixity.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import json
import logging
import os
import sys
import traceback
from argparse import ArgumentParser
from datetime import datetime
from datetime import timezone
from time import sleep
from uuid import uuid4

Expand All @@ -22,7 +25,7 @@
raise ArgumentError("An AIP UUID must be specified when scanning a single AIP")


def parse_arguments():
def parse_arguments(argv):
parser = ArgumentParser()
parser.add_argument("command", choices=["scan", "scanall"], help="Command to run.")
parser.add_argument("aip", nargs="?", help="If 'scan', UUID of the AIP to scan")
Expand All @@ -45,7 +48,7 @@
action="store_true",
help="Add a timestamp to the beginning of each line of output.",
)
args = parser.parse_args()
args = parser.parse_args(argv)

validate_arguments(args)
return args
Expand Down Expand Up @@ -100,11 +103,11 @@
ss_user,
ss_key,
session,
logger,
report_url=None,
report_auth=(),
session_id=None,
force_local=False,
timestamps=False,
):
"""
Instruct the storage service to scan a single AIP.
Expand All @@ -117,11 +120,11 @@
:param str ss_url: The base URL to a storage service installation.
:param str ss_user: Storage service user to authenticate as
:param str ss_key: API key of the storage service user
:param Logger logger: Logger to print output.
:param str report_url: The base URL to a server to which the report will be POSTed after the scan completes. If absent, the report will not be transmitted.
:param report_auth: Authentication for the report_url. Tupel of (user, password) for HTTP auth.
:param session_id: Identifier for this session, allowing every scan from one run to be identified.
:param bool force_local: If True, will request the Storage Service to perform a local fixity check, instead of using the Space's fixity (if available).
:param bool timestamps: If True, will add a timestamp to the beginning of each line of output.
"""

# Ensure the storage service knows about this AIP first;
Expand All @@ -142,10 +145,7 @@
session_id=session_id,
)
except reporting.ReportServiceException:
utils.pyprint(
f"Unable to POST pre-scan report to {report_url}", timestamps=timestamps
)

logger.log(logging.WARNING, f"Unable to POST pre-scan report to {report_url}")
try:
status, report = storage_service.scan_aip(
aip,
Expand All @@ -157,11 +157,10 @@
force_local=force_local,
)
report_data = json.loads(report.report)
utils.pyprint(
scan_message(aip, status, report_data["message"]), timestamps=timestamps
)
logger.log(logging.WARNING, scan_message(aip, status, report_data["message"]))
except Exception as e:
utils.pyprint(str(e), timestamps=timestamps)
logger.log(logging.WARNING, str(e))

status = None
if hasattr(e, "report") and e.report:
report = e.report
Expand Down Expand Up @@ -190,11 +189,10 @@
aip, report, report_url, report_auth=report_auth, session_id=session_id
)
except reporting.ReportServiceException:
utils.pyprint(
logger.log(
logging.WARNING,
f"Unable to POST report for AIP {aip} to remote service",
timestamps=timestamps,
replaceafill marked this conversation as resolved.
Show resolved Hide resolved
)

if report:
session.add(report)

Expand All @@ -206,23 +204,23 @@
ss_user,
ss_key,
session,
logger,
report_url=None,
report_auth=(),
throttle_time=0,
force_local=False,
timestamps=False,
):
"""
Run a fixity scan on every AIP in a storage service instance.

:param str ss_url: The base URL to a storage service installation.
:param str ss_user: Storage service user to authenticate as
:param str ss_key: API key of the storage service user
:param Logger logger: Logger to print output.
:param str report_url: The base URL to a server to which the report will be POSTed after the scan completes. If absent, the report will not be transmitted.
:param report_auth: Authentication for the report_url. Tupel of (user, password) for HTTP auth.
:param int throttle_time: Time to wait between scans.
:param bool force_local: If True, will request the Storage Service to perform a local fixity check, instead of using the Space's fixity (if available).
:param bool timestamps: If True, will add a timestamp to the beginning of each line of output.
"""
success = True

Expand All @@ -243,33 +241,60 @@
ss_user,
ss_key,
session,
logger,
report_url=report_url,
report_auth=report_auth,
session_id=session_id,
force_local=force_local,
timestamps=timestamps,
)
if not scan_success:
success = False
except Exception as e:
utils.pyprint(
logger.log(
logging.WARNING,
f"Internal error encountered while scanning AIP {aip['uuid']} ({type(e).__name__})",
timestamps=timestamps,
)
if throttle_time:
sleep(throttle_time)

if count > 0:
utils.pyprint(f"Successfully scanned {count} AIPs", timestamps=timestamps)
replaceafill marked this conversation as resolved.
Show resolved Hide resolved

logger.log(logging.WARNING, f"Successfully scanned {count} AIPs")
return success


def main():
class UTCFormatter(logging.Formatter):
def formatTime(self, record, datefmt=None):
return datetime.fromtimestamp(record.created, tz=timezone.utc).strftime(
"%Y-%m-%d %H:%M:%S %Z"
)


def get_logger() -> logging.Logger:
logger = logging.getLogger("fixity")
logger.setLevel(logging.WARNING)
return logger


def get_handler(stream, timestamps):
stderr_handler = logging.StreamHandler(stream=stream)
if timestamps:
message_format = UTCFormatter("[%(asctime)s] %(message)s")
else:
message_format = logging.Formatter("%(message)s")
stderr_handler.setFormatter(message_format)
return stderr_handler


def main(argv=None, logger=None, stream=None):
if logger is None:
logger = get_logger()
if stream is None:
stream = sys.stderr

success = 0

try:
args = parse_arguments()
args = parse_arguments(argv)
except ArgumentError as e:
return e

Expand All @@ -278,6 +303,7 @@
except ArgumentError as e:
return e

logger.addHandler(get_handler(stream=stream, timestamps=args.timestamps))
session = Session()

status = False
Expand All @@ -296,11 +322,11 @@
args.ss_user,
args.ss_key,
session,
logger,
report_url=report_url,
report_auth=auth,
throttle_time=args.throttle,
force_local=args.force_local,
timestamps=args.timestamps,
)
elif args.command == "scan":
session_id = str(uuid4())
Expand All @@ -310,11 +336,11 @@
args.ss_user,
args.ss_key,
session,
logger,
report_url=report_url,
report_auth=auth,
session_id=session_id,
force_local=args.force_local,
timestamps=args.timestamps,
)
else:
return Exception(f'Error: "{args.command}" is not a valid command.')
Expand All @@ -339,4 +365,4 @@


if __name__ == "__main__":
sys.exit(main())
sys.exit(main(sys.argv[1:], get_logger(), sys.stderr))

Check warning on line 368 in fixity/fixity.py

View check run for this annotation

Codecov / codecov/patch

fixity/fixity.py#L368

Added line #L368 was not covered by tests
11 changes: 0 additions & 11 deletions fixity/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import sys
from datetime import datetime
from datetime import timezone
from uuid import UUID
Expand Down Expand Up @@ -34,13 +33,3 @@ def check_valid_uuid(uuid):

def utcnow():
return datetime.now(timezone.utc)


def format_timestamp(t):
return t.strftime("%Y-%m-%d %H:%M:%S %Z")


def pyprint(message, **kwargs):
if kwargs.get("timestamps"):
message = f"[{format_timestamp(utcnow())}] {message}"
print(message, file=sys.stderr)
Loading