Skip to content

Commit 62cd0de

Browse files
committed
Make git trace2 logging errors conditional on verbose mode.
Add a verbose attribute to the EventLog class, defaulting to False. Error messages printed to sys.stderr within the EventLog.Write method are now guarded by this verbose flag. In main.py, set EventLog.verbose to True if the command-line --verbose option is used. This prevents trace2 logging failures from being printed to stderr unless verbose output is explicitly requested. PROMPT=convert all git trace2 logging print messages to verbose only logging BUG: b/479811034 Change-Id: I8757ee52117d766f2f3ec47856db64cc4f51143c Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/547542 Tested-by: Sam Saccone <samccone@google.com> Reviewed-by: Julia Tuttle <juliatuttle@google.com> Reviewed-by: Gavin Mak <gavinmak@google.com>
1 parent b60512a commit 62cd0de

4 files changed

Lines changed: 162 additions & 53 deletions

File tree

git_trace2_event_log_base.py

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def __init__(
6868
global p_init_count
6969
p_init_count += 1
7070
self._log = []
71+
self.verbose = False
7172
# Try to get session-id (sid) from environment (setup in repo launcher).
7273
KEY = "GIT_TRACE2_PARENT_SID"
7374
if env is None:
@@ -309,10 +310,12 @@ def Write(self, path=None):
309310
# ignore the attempt and continue to DGRAM below. Otherwise,
310311
# issue a warning.
311312
if err.errno != errno.EPROTOTYPE:
312-
print(
313-
f"repo: warning: git trace2 logging failed: {err}",
314-
file=sys.stderr,
315-
)
313+
if self.verbose:
314+
print(
315+
"repo: warning: git trace2 logging failed:",
316+
f"{err}",
317+
file=sys.stderr,
318+
)
316319
return None
317320
if socket_type == socket.SOCK_DGRAM or socket_type is None:
318321
try:
@@ -322,18 +325,20 @@ def Write(self, path=None):
322325
self._WriteLog(lambda bs: sock.sendto(bs, path))
323326
return f"af_unix:dgram:{path}"
324327
except OSError as err:
325-
print(
326-
f"repo: warning: git trace2 logging failed: {err}",
327-
file=sys.stderr,
328-
)
328+
if self.verbose:
329+
print(
330+
f"repo: warning: git trace2 logging failed: {err}",
331+
file=sys.stderr,
332+
)
329333
return None
330334
# Tried to open a socket but couldn't connect (SOCK_STREAM) or write
331335
# (SOCK_DGRAM).
332-
print(
333-
"repo: warning: git trace2 logging failed: could not write to "
334-
"socket",
335-
file=sys.stderr,
336-
)
336+
if self.verbose:
337+
print(
338+
"repo: warning: git trace2 logging failed: could not"
339+
"write to socket",
340+
file=sys.stderr,
341+
)
337342
return None
338343

339344
# Path is an absolute path
@@ -348,9 +353,10 @@ def Write(self, path=None):
348353
self._WriteLog(f.write)
349354
log_path = f.name
350355
except FileExistsError as err:
351-
print(
352-
"repo: warning: git trace2 logging failed: %r" % err,
353-
file=sys.stderr,
354-
)
356+
if self.verbose:
357+
print(
358+
"repo: warning: git trace2 logging failed: %r" % err,
359+
file=sys.stderr,
360+
)
355361
return None
356362
return log_path

main.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,9 @@ def _RunLong(self, name, gopts, argv, git_trace2_event_log):
337337
)
338338
return 1
339339

340+
cmd.CommonValidateOptions(copts, cargs)
341+
git_trace2_event_log.verbose = copts.verbose
342+
340343
if gopts.pager is not False and not isinstance(cmd, InteractiveCommand):
341344
config = cmd.client.globalConfig
342345
if gopts.pager:
@@ -359,7 +362,6 @@ def execute_command_helper():
359362
Execute the subcommand.
360363
"""
361364
nonlocal result
362-
cmd.CommonValidateOptions(copts, cargs)
363365
cmd.ValidateOptions(copts, cargs)
364366

365367
this_manifest_only = copts.this_manifest_only

tests/test_git_trace2_event_log.py

Lines changed: 89 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
"""Unittests for the git_trace2_event_log.py module."""
1616

17+
import contextlib
18+
import io
1719
import json
1820
import os
1921
import socket
@@ -65,13 +67,13 @@ class EventLogTestCase(unittest.TestCase):
6567

6668
def setUp(self):
6769
"""Load the event_log module every time."""
68-
self._event_log_module = None
70+
self._event_log = None
6971
# By default we initialize with the expected case where
7072
# repo launches us (so GIT_TRACE2_PARENT_SID is set).
7173
env = {
7274
self.PARENT_SID_KEY: self.PARENT_SID_VALUE,
7375
}
74-
self._event_log_module = git_trace2_event_log.EventLog(env=env)
76+
self._event_log = git_trace2_event_log.EventLog(env=env)
7577
self._log_data = None
7678

7779
def verifyCommonKeys(
@@ -112,13 +114,13 @@ def remove_prefix(self, s, prefix):
112114

113115
def test_initial_state_with_parent_sid(self):
114116
"""Test initial state when 'GIT_TRACE2_PARENT_SID' is set by parent."""
115-
self.assertRegex(self._event_log_module.full_sid, self.FULL_SID_REGEX)
117+
self.assertRegex(self._event_log.full_sid, self.FULL_SID_REGEX)
116118

117119
def test_initial_state_no_parent_sid(self):
118120
"""Test initial state when 'GIT_TRACE2_PARENT_SID' is not set."""
119121
# Setup an empty environment dict (no parent sid).
120-
self._event_log_module = git_trace2_event_log.EventLog(env={})
121-
self.assertRegex(self._event_log_module.full_sid, self.SELF_SID_REGEX)
122+
self._event_log = git_trace2_event_log.EventLog(env={})
123+
self.assertRegex(self._event_log.full_sid, self.SELF_SID_REGEX)
122124

123125
def test_version_event(self):
124126
"""Test 'version' event data is valid.
@@ -130,7 +132,7 @@ def test_version_event(self):
130132
<version event>
131133
"""
132134
with tempfile.TemporaryDirectory(prefix="event_log_tests") as tempdir:
133-
log_path = self._event_log_module.Write(path=tempdir)
135+
log_path = self._event_log.Write(path=tempdir)
134136
self._log_data = self.readLog(log_path)
135137

136138
# A log with no added events should only have the version entry.
@@ -150,9 +152,9 @@ def test_start_event(self):
150152
<version event>
151153
<start event>
152154
"""
153-
self._event_log_module.StartEvent([])
155+
self._event_log.StartEvent([])
154156
with tempfile.TemporaryDirectory(prefix="event_log_tests") as tempdir:
155-
log_path = self._event_log_module.Write(path=tempdir)
157+
log_path = self._event_log.Write(path=tempdir)
156158
self._log_data = self.readLog(log_path)
157159

158160
self.assertEqual(len(self._log_data), 2)
@@ -172,9 +174,9 @@ def test_exit_event_result_none(self):
172174
<version event>
173175
<exit event>
174176
"""
175-
self._event_log_module.ExitEvent(None)
177+
self._event_log.ExitEvent(None)
176178
with tempfile.TemporaryDirectory(prefix="event_log_tests") as tempdir:
177-
log_path = self._event_log_module.Write(path=tempdir)
179+
log_path = self._event_log.Write(path=tempdir)
178180
self._log_data = self.readLog(log_path)
179181

180182
self.assertEqual(len(self._log_data), 2)
@@ -193,9 +195,9 @@ def test_exit_event_result_integer(self):
193195
<version event>
194196
<exit event>
195197
"""
196-
self._event_log_module.ExitEvent(2)
198+
self._event_log.ExitEvent(2)
197199
with tempfile.TemporaryDirectory(prefix="event_log_tests") as tempdir:
198-
log_path = self._event_log_module.Write(path=tempdir)
200+
log_path = self._event_log.Write(path=tempdir)
199201
self._log_data = self.readLog(log_path)
200202

201203
self.assertEqual(len(self._log_data), 2)
@@ -213,11 +215,9 @@ def test_command_event(self):
213215
<version event>
214216
<command event>
215217
"""
216-
self._event_log_module.CommandEvent(
217-
name="repo", subcommands=["init", "this"]
218-
)
218+
self._event_log.CommandEvent(name="repo", subcommands=["init", "this"])
219219
with tempfile.TemporaryDirectory(prefix="event_log_tests") as tempdir:
220-
log_path = self._event_log_module.Write(path=tempdir)
220+
log_path = self._event_log.Write(path=tempdir)
221221
self._log_data = self.readLog(log_path)
222222

223223
self.assertEqual(len(self._log_data), 2)
@@ -241,10 +241,10 @@ def test_def_params_event_repo_config(self):
241241
"repo.partialclone": "true",
242242
"repo.partialclonefilter": "blob:none",
243243
}
244-
self._event_log_module.DefParamRepoEvents(config)
244+
self._event_log.DefParamRepoEvents(config)
245245

246246
with tempfile.TemporaryDirectory(prefix="event_log_tests") as tempdir:
247-
log_path = self._event_log_module.Write(path=tempdir)
247+
log_path = self._event_log.Write(path=tempdir)
248248
self._log_data = self.readLog(log_path)
249249

250250
self.assertEqual(len(self._log_data), 3)
@@ -268,10 +268,10 @@ def test_def_params_event_no_repo_config(self):
268268
"git.foo": "bar",
269269
"git.core.foo2": "baz",
270270
}
271-
self._event_log_module.DefParamRepoEvents(config)
271+
self._event_log.DefParamRepoEvents(config)
272272

273273
with tempfile.TemporaryDirectory(prefix="event_log_tests") as tempdir:
274-
log_path = self._event_log_module.Write(path=tempdir)
274+
log_path = self._event_log.Write(path=tempdir)
275275
self._log_data = self.readLog(log_path)
276276

277277
self.assertEqual(len(self._log_data), 1)
@@ -292,10 +292,10 @@ def test_data_event_config(self):
292292
"repo.syncstate.superproject.sys.argv": ["--", "sync", "protobuf"],
293293
}
294294
prefix_value = "prefix"
295-
self._event_log_module.LogDataConfigEvents(config, prefix_value)
295+
self._event_log.LogDataConfigEvents(config, prefix_value)
296296

297297
with tempfile.TemporaryDirectory(prefix="event_log_tests") as tempdir:
298-
log_path = self._event_log_module.Write(path=tempdir)
298+
log_path = self._event_log.Write(path=tempdir)
299299
self._log_data = self.readLog(log_path)
300300

301301
self.assertEqual(len(self._log_data), 5)
@@ -311,7 +311,7 @@ def test_data_event_config(self):
311311
key = self.remove_prefix(key, f"{prefix_value}/")
312312
value = event["value"]
313313
self.assertEqual(
314-
self._event_log_module.GetDataEventName(value), event["event"]
314+
self._event_log.GetDataEventName(value), event["event"]
315315
)
316316
self.assertTrue(key in config and value == config[key])
317317

@@ -324,9 +324,9 @@ def test_error_event(self):
324324
"""
325325
msg = "invalid option: --cahced"
326326
fmt = "invalid option: %s"
327-
self._event_log_module.ErrorEvent(msg, fmt)
327+
self._event_log.ErrorEvent(msg, fmt)
328328
with tempfile.TemporaryDirectory(prefix="event_log_tests") as tempdir:
329-
log_path = self._event_log_module.Write(path=tempdir)
329+
log_path = self._event_log.Write(path=tempdir)
330330
self._log_data = self.readLog(log_path)
331331

332332
self.assertEqual(len(self._log_data), 2)
@@ -341,32 +341,32 @@ def test_error_event(self):
341341

342342
def test_write_with_filename(self):
343343
"""Test Write() with a path to a file exits with None."""
344-
self.assertIsNone(self._event_log_module.Write(path="path/to/file"))
344+
self.assertIsNone(self._event_log.Write(path="path/to/file"))
345345

346346
def test_write_with_git_config(self):
347347
"""Test Write() uses the git config path when 'git config' call
348348
succeeds."""
349349
with tempfile.TemporaryDirectory(prefix="event_log_tests") as tempdir:
350350
with mock.patch.object(
351-
self._event_log_module,
351+
self._event_log,
352352
"_GetEventTargetPath",
353353
return_value=tempdir,
354354
):
355355
self.assertEqual(
356-
os.path.dirname(self._event_log_module.Write()), tempdir
356+
os.path.dirname(self._event_log.Write()), tempdir
357357
)
358358

359359
def test_write_no_git_config(self):
360360
"""Test Write() with no git config variable present exits with None."""
361361
with mock.patch.object(
362-
self._event_log_module, "_GetEventTargetPath", return_value=None
362+
self._event_log, "_GetEventTargetPath", return_value=None
363363
):
364-
self.assertIsNone(self._event_log_module.Write())
364+
self.assertIsNone(self._event_log.Write())
365365

366366
def test_write_non_string(self):
367367
"""Test Write() with non-string type for |path| throws TypeError."""
368368
with self.assertRaises(TypeError):
369-
self._event_log_module.Write(path=1234)
369+
self._event_log.Write(path=1234)
370370

371371
@unittest.skipIf(not hasattr(socket, "AF_UNIX"), "Requires AF_UNIX sockets")
372372
def test_write_socket(self):
@@ -389,10 +389,8 @@ def test_write_socket(self):
389389
with server_ready:
390390
server_ready.wait(timeout=120)
391391

392-
self._event_log_module.StartEvent([])
393-
path = self._event_log_module.Write(
394-
path=f"af_unix:{socket_path}"
395-
)
392+
self._event_log.StartEvent([])
393+
path = self._event_log.Write(path=f"af_unix:{socket_path}")
396394
finally:
397395
server_thread.join(timeout=5)
398396

@@ -405,3 +403,59 @@ def test_write_socket(self):
405403
# Check for 'start' event specific fields.
406404
self.assertIn("argv", start_event)
407405
self.assertIsInstance(start_event["argv"], list)
406+
407+
408+
class EventLogVerboseTestCase(unittest.TestCase):
409+
"""TestCase for the EventLog module verbose logging."""
410+
411+
def setUp(self):
412+
self._event_log = git_trace2_event_log.EventLog(env={})
413+
414+
def test_write_socket_error_no_verbose(self):
415+
"""Test Write() suppression of socket errors when not verbose."""
416+
self._event_log.verbose = False
417+
with contextlib.redirect_stderr(
418+
io.StringIO()
419+
) as mock_stderr, mock.patch("socket.socket", side_effect=OSError):
420+
self._event_log.Write(path="af_unix:stream:/tmp/test_sock")
421+
self.assertEqual(mock_stderr.getvalue(), "")
422+
423+
def test_write_socket_error_verbose(self):
424+
"""Test Write() printing of socket errors when verbose."""
425+
self._event_log.verbose = True
426+
with contextlib.redirect_stderr(
427+
io.StringIO()
428+
) as mock_stderr, mock.patch(
429+
"socket.socket", side_effect=OSError("Mock error")
430+
):
431+
self._event_log.Write(path="af_unix:stream:/tmp/test_sock")
432+
self.assertIn(
433+
"git trace2 logging failed: Mock error",
434+
mock_stderr.getvalue(),
435+
)
436+
437+
def test_write_file_error_no_verbose(self):
438+
"""Test Write() suppression of file errors when not verbose."""
439+
self._event_log.verbose = False
440+
with contextlib.redirect_stderr(
441+
io.StringIO()
442+
) as mock_stderr, mock.patch(
443+
"tempfile.NamedTemporaryFile", side_effect=FileExistsError
444+
):
445+
self._event_log.Write(path="/tmp")
446+
self.assertEqual(mock_stderr.getvalue(), "")
447+
448+
def test_write_file_error_verbose(self):
449+
"""Test Write() printing of file errors when verbose."""
450+
self._event_log.verbose = True
451+
with contextlib.redirect_stderr(
452+
io.StringIO()
453+
) as mock_stderr, mock.patch(
454+
"tempfile.NamedTemporaryFile",
455+
side_effect=FileExistsError("Mock error"),
456+
):
457+
self._event_log.Write(path="/tmp")
458+
self.assertIn(
459+
"git trace2 logging failed: FileExistsError",
460+
mock_stderr.getvalue(),
461+
)

0 commit comments

Comments
 (0)