Skip to content

Commit 992682f

Browse files
Create argument to display timestamps
The --timestamps option will display the date and time to the beginning of each line of output.
1 parent 86c6d71 commit 992682f

File tree

6 files changed

+78
-7
lines changed

6 files changed

+78
-7
lines changed

docs/fixity.1

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ Request the Storage Service performs a local fixity check, instead of using the
3535
\fB\-\-debug\fR
3636
Print extra debugging output\.
3737
.
38+
.TP
39+
\fB\-\-timestamps\fR
40+
Add a timestamp to the beginning of each line of output\.
41+
.
3842
.SH "COMMANDS"
3943
.
4044
.TP

docs/fixity.1.html

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/fixity.1.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ running; see the section on _ENVIRONMENT VARIABLES_ for information.
3535
* `--debug`:
3636
Print extra debugging output.
3737

38+
* `--timestamps`:
39+
It adds a timestamp to the beginning of each line of output.
40+
3841
## COMMANDS
3942

4043
* `scan <UUID>`:

fixity/fixity.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ def parse_arguments():
4040
action="store_true",
4141
help="Force a local fixity check on the Storage Service.",
4242
)
43+
parser.add_argument(
44+
"--timestamps",
45+
action="store_true",
46+
help="Add a timestamp to the beginning of each line of output.",
47+
)
4348
args = parser.parse_args()
4449

4550
validate_arguments(args)
@@ -99,6 +104,7 @@ def scan(
99104
report_auth=(),
100105
session_id=None,
101106
force_local=False,
107+
timestamps=False,
102108
):
103109
"""
104110
Instruct the storage service to scan a single AIP.
@@ -114,7 +120,8 @@ def scan(
114120
: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.
115121
:param report_auth: Authentication for the report_url. Tupel of (user, password) for HTTP auth.
116122
:param session_id: Identifier for this session, allowing every scan from one run to be identified.
117-
:param bool force_local: If True, will will request the Storage Service to perform a local fixity check, instead of using the Space's fixity (if available).
123+
: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).
124+
:param bool timestamps: If True, will add a timestamp to the beginning of each line of output.
118125
"""
119126

120127
# Ensure the storage service knows about this AIP first;
@@ -135,7 +142,9 @@ def scan(
135142
session_id=session_id,
136143
)
137144
except reporting.ReportServiceException:
138-
utils.pyprint(f"Unable to POST pre-scan report to {report_url}")
145+
utils.pyprint(
146+
f"Unable to POST pre-scan report to {report_url}", timestamps=timestamps
147+
)
139148

140149
try:
141150
status, report = storage_service.scan_aip(
@@ -148,9 +157,11 @@ def scan(
148157
force_local=force_local,
149158
)
150159
report_data = json.loads(report.report)
151-
utils.pyprint(scan_message(aip, status, report_data["message"]))
160+
utils.pyprint(
161+
scan_message(aip, status, report_data["message"]), timestamps=timestamps
162+
)
152163
except Exception as e:
153-
utils.pyprint(str(e))
164+
utils.pyprint(str(e), timestamps=timestamps)
154165
status = None
155166
if hasattr(e, "report") and e.report:
156167
report = e.report
@@ -179,7 +190,10 @@ def scan(
179190
aip, report, report_url, report_auth=report_auth, session_id=session_id
180191
)
181192
except reporting.ReportServiceException:
182-
utils.pyprint(f"Unable to POST report for AIP {aip} to remote service")
193+
utils.pyprint(
194+
f"Unable to POST report for AIP {aip} to remote service",
195+
timestamps=timestamps,
196+
)
183197

184198
if report:
185199
session.add(report)
@@ -196,6 +210,7 @@ def scanall(
196210
report_auth=(),
197211
throttle_time=0,
198212
force_local=False,
213+
timestamps=False,
199214
):
200215
"""
201216
Run a fixity scan on every AIP in a storage service instance.
@@ -206,7 +221,8 @@ def scanall(
206221
: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.
207222
:param report_auth: Authentication for the report_url. Tupel of (user, password) for HTTP auth.
208223
:param int throttle_time: Time to wait between scans.
209-
:param bool force_local: If True, will will request the Storage Service to perform a local fixity check, instead of using the Space's fixity (if available).
224+
: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).
225+
:param bool timestamps: If True, will add a timestamp to the beginning of each line of output.
210226
"""
211227
success = True
212228

@@ -231,19 +247,21 @@ def scanall(
231247
report_auth=report_auth,
232248
session_id=session_id,
233249
force_local=force_local,
250+
timestamps=timestamps,
234251
)
235252
if not scan_success:
236253
success = False
237254
except Exception as e:
238255
utils.pyprint(
239256
f"Internal error encountered while scanning AIP {aip['uuid']} ({type(e).__name__})",
240257
file=sys.stdout,
258+
timestamps=timestamps,
241259
)
242260
if throttle_time:
243261
sleep(throttle_time)
244262

245263
if count > 0:
246-
utils.pyprint(f"Successfully scanned {count} AIPs")
264+
utils.pyprint(f"Successfully scanned {count} AIPs", timestamps=timestamps)
247265

248266
return success
249267

@@ -283,6 +301,7 @@ def main():
283301
report_auth=auth,
284302
throttle_time=args.throttle,
285303
force_local=args.force_local,
304+
timestamps=args.timestamps,
286305
)
287306
elif args.command == "scan":
288307
session_id = str(uuid4())
@@ -296,6 +315,7 @@ def main():
296315
report_auth=auth,
297316
session_id=session_id,
298317
force_local=args.force_local,
318+
timestamps=args.timestamps,
299319
)
300320
else:
301321
return Exception(f'Error: "{args.command}" is not a valid command.')

fixity/utils.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,11 @@ def utcnow():
3636
return datetime.now(timezone.utc)
3737

3838

39+
def format_timestamp(t):
40+
return t.strftime("%Y-%m-%d %H:%M:%S %Z")
41+
42+
3943
def pyprint(message, **kwargs):
44+
if kwargs.get("timestamps"):
45+
message = f"[{format_timestamp(utcnow())}] {message}"
4046
print(message, file=kwargs.get("file", sys.stderr))

tests/test_fixity.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,43 @@ def test_scan(_get, mock_check_fixity):
7474
]
7575

7676

77+
@mock.patch("fixity.utils.utcnow")
78+
@mock.patch("requests.get")
79+
def test_scan_if_timestamps_argument_is_passed(_get, utcnow, mock_check_fixity, capsys):
80+
_get.side_effect = mock_check_fixity
81+
aip_id = uuid.uuid4()
82+
timestamp = 1514775600
83+
utcnow.return_value = datetime.fromtimestamp(timestamp, timezone.utc)
84+
85+
response = fixity.scan(
86+
aip=str(aip_id),
87+
ss_url=STORAGE_SERVICE_URL,
88+
ss_user=STORAGE_SERVICE_USER,
89+
ss_key=STORAGE_SERVICE_KEY,
90+
session=SESSION,
91+
timestamps=True,
92+
)
93+
94+
assert response is True
95+
96+
captured = capsys.readouterr()
97+
assert captured.out == ""
98+
assert (
99+
captured.err.strip()
100+
== f"[2018-01-01 03:00:00 UTC] Fixity scan succeeded for AIP: {aip_id}"
101+
)
102+
assert _get.mock_calls == [
103+
mock.call(
104+
f"{STORAGE_SERVICE_URL}api/v2/file/{aip_id}/",
105+
params={"username": STORAGE_SERVICE_USER, "api_key": STORAGE_SERVICE_KEY},
106+
),
107+
mock.call(
108+
f"{STORAGE_SERVICE_URL}api/v2/file/{aip_id}/check_fixity/",
109+
params={"username": STORAGE_SERVICE_USER, "api_key": STORAGE_SERVICE_KEY},
110+
),
111+
]
112+
113+
77114
@mock.patch("fixity.utils.utcnow")
78115
@mock.patch("requests.get")
79116
@mock.patch(

0 commit comments

Comments
 (0)