event_log.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #
  2. # Copyright (C) 2017 The Android Open Source Project
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. from __future__ import print_function
  16. import json
  17. import multiprocessing
  18. TASK_COMMAND = 'command'
  19. TASK_SYNC_NETWORK = 'sync-network'
  20. TASK_SYNC_LOCAL = 'sync-local'
  21. class EventLog(object):
  22. """Event log that records events that occurred during a repo invocation.
  23. Events are written to the log as a consecutive JSON entries, one per line.
  24. Each entry contains the following keys:
  25. - id: A ('RepoOp', ID) tuple, suitable for storing in a datastore.
  26. The ID is only unique for the invocation of the repo command.
  27. - name: Name of the object being operated upon.
  28. - task_name: The task that was performed.
  29. - start: Timestamp of when the operation started.
  30. - finish: Timestamp of when the operation finished.
  31. - success: Boolean indicating if the operation was successful.
  32. - try_count: A counter indicating the try count of this task.
  33. Optionally:
  34. - parent: A ('RepoOp', ID) tuple indicating the parent event for nested
  35. events.
  36. Valid task_names include:
  37. - command: The invocation of a subcommand.
  38. - sync-network: The network component of a sync command.
  39. - sync-local: The local component of a sync command.
  40. Specific tasks may include additional informational properties.
  41. """
  42. def __init__(self):
  43. """Initializes the event log."""
  44. self._log = []
  45. self._parent = None
  46. def Add(self, name, task_name, start, finish=None, success=None,
  47. try_count=1, kind='RepoOp'):
  48. """Add an event to the log.
  49. Args:
  50. name: Name of the object being operated upon.
  51. task_name: A sub-task that was performed for name.
  52. start: Timestamp of when the operation started.
  53. finish: Timestamp of when the operation finished.
  54. success: Boolean indicating if the operation was successful.
  55. try_count: A counter indicating the try count of this task.
  56. kind: The kind of the object for the unique identifier.
  57. Returns:
  58. A dictionary of the event added to the log.
  59. """
  60. event = {
  61. 'id': (kind, _NextEventId()),
  62. 'name': name,
  63. 'task_name': task_name,
  64. 'start_time': start,
  65. 'try': try_count,
  66. }
  67. if self._parent:
  68. event['parent'] = self._parent['id']
  69. if success is not None or finish is not None:
  70. self.FinishEvent(event, finish, success)
  71. self._log.append(event)
  72. return event
  73. def AddSync(self, project, task_name, start, finish, success):
  74. """Add a event to the log for a sync command.
  75. Args:
  76. project: Project being synced.
  77. task_name: A sub-task that was performed for name.
  78. One of (TASK_SYNC_NETWORK, TASK_SYNC_LOCAL)
  79. start: Timestamp of when the operation started.
  80. finish: Timestamp of when the operation finished.
  81. success: Boolean indicating if the operation was successful.
  82. Returns:
  83. A dictionary of the event added to the log.
  84. """
  85. event = self.Add(project.relpath, task_name, start, finish, success)
  86. if event is not None:
  87. event['project'] = project.name
  88. if project.revisionExpr:
  89. event['revision'] = project.revisionExpr
  90. if project.remote.url:
  91. event['project_url'] = project.remote.url
  92. if project.remote.fetchUrl:
  93. event['remote_url'] = project.remote.fetchUrl
  94. try:
  95. event['git_hash'] = project.GetCommitRevisionId()
  96. except Exception:
  97. pass
  98. return event
  99. def GetStatusString(self, success):
  100. """Converst a boolean success to a status string.
  101. Args:
  102. success: Boolean indicating if the operation was successful.
  103. Returns:
  104. status string.
  105. """
  106. return 'pass' if success else 'fail'
  107. def FinishEvent(self, event, finish, success):
  108. """Finishes an incomplete event.
  109. Args:
  110. event: An event that has been added to the log.
  111. finish: Timestamp of when the operation finished.
  112. success: Boolean indicating if the operation was successful.
  113. Returns:
  114. A dictionary of the event added to the log.
  115. """
  116. event['status'] = self.GetStatusString(success)
  117. event['finish_time'] = finish
  118. return event
  119. def SetParent(self, event):
  120. """Set a parent event for all new entities.
  121. Args:
  122. event: The event to use as a parent.
  123. """
  124. self._parent = event
  125. def Write(self, filename):
  126. """Writes the log out to a file.
  127. Args:
  128. filename: The file to write the log to.
  129. """
  130. with open(filename, 'w+') as f:
  131. for e in self._log:
  132. json.dump(e, f, sort_keys=True)
  133. f.write('\n')
  134. # An integer id that is unique across this invocation of the program.
  135. _EVENT_ID = multiprocessing.Value('i', 1)
  136. def _NextEventId():
  137. """Helper function for grabbing the next unique id.
  138. Returns:
  139. A unique, to this invocation of the program, integer id.
  140. """
  141. with _EVENT_ID.get_lock():
  142. val = _EVENT_ID.value
  143. _EVENT_ID.value += 1
  144. return val