send-error-report 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. #!/usr/bin/env python
  2. # Sends an error report (if the report-error class was enabled) to a
  3. # remote server.
  4. #
  5. # Copyright (C) 2013 Intel Corporation
  6. # Author: Andreea Proca <andreea.b.proca@intel.com>
  7. # Author: Michael Wood <michael.g.wood@intel.com>
  8. import urllib2
  9. import sys
  10. import json
  11. import os
  12. import subprocess
  13. import argparse
  14. import logging
  15. version = "0.3"
  16. log = logging.getLogger("send-error-report")
  17. logging.basicConfig(format='%(levelname)s: %(message)s')
  18. def getPayloadLimit(url):
  19. req = urllib2.Request(url, None)
  20. try:
  21. response = urllib2.urlopen(req)
  22. except urllib2.URLError as e:
  23. # Use this opportunity to bail out if we can't even contact the server
  24. log.error("Could not contact server: " + url)
  25. log.error(e.reason)
  26. sys.exit(1)
  27. try:
  28. ret = json.loads(response.read())
  29. max_log_size = ret.get('max_log_size', 0)
  30. return int(max_log_size)
  31. except:
  32. pass
  33. return 0
  34. def ask_for_contactdetails():
  35. print("Please enter your name and your email (optionally), they'll be saved in the file you send.")
  36. username = raw_input("Name (required): ")
  37. email = raw_input("E-mail (not required): ")
  38. return username, email
  39. def edit_content(json_file_path):
  40. edit = raw_input("Review information before sending? (y/n): ")
  41. if 'y' in edit or 'Y' in edit:
  42. editor = os.environ.get('EDITOR', None)
  43. if editor:
  44. subprocess.check_call([editor, json_file_path])
  45. else:
  46. log.error("Please set your EDITOR value")
  47. sys.exit(1)
  48. return True
  49. return False
  50. def prepare_data(args):
  51. # attempt to get the max_log_size from the server's settings
  52. max_log_size = getPayloadLimit("http://"+args.server+"/ClientPost/JSON")
  53. if not os.path.isfile(args.error_file):
  54. log.error("No data file found.")
  55. sys.exit(1)
  56. home = os.path.expanduser("~")
  57. userfile = os.path.join(home, ".oe-send-error")
  58. try:
  59. with open(userfile, 'r') as userfile_fp:
  60. if len(args.name) == 0:
  61. args.name = userfile_fp.readline()
  62. else:
  63. #use empty readline to increment the fp
  64. userfile_fp.readline()
  65. if len(args.email) == 0:
  66. args.email = userfile_fp.readline()
  67. except:
  68. pass
  69. if args.assume_yes == True and len(args.name) == 0:
  70. log.error("Name needs to be provided either via "+userfile+" or as an argument (-n).")
  71. sys.exit(1)
  72. while len(args.name) <= 0 and len(args.name) < 50:
  73. print("\nName needs to be given and must not more than 50 characters.")
  74. args.name, args.email = ask_for_contactdetails()
  75. with open(userfile, 'w') as userfile_fp:
  76. userfile_fp.write(args.name.strip() + "\n")
  77. userfile_fp.write(args.email.strip() + "\n")
  78. with open(args.error_file, 'r') as json_fp:
  79. data = json_fp.read()
  80. jsondata = json.loads(data)
  81. jsondata['username'] = args.name.strip()
  82. jsondata['email'] = args.email.strip()
  83. jsondata['link_back'] = args.link_back.strip()
  84. # If we got a max_log_size then use this to truncate to get the last
  85. # max_log_size bytes from the end
  86. if max_log_size != 0:
  87. for fail in jsondata['failures']:
  88. if len(fail['log']) > max_log_size:
  89. print "Truncating log to allow for upload"
  90. fail['log'] = fail['log'][-max_log_size:]
  91. data = json.dumps(jsondata, indent=4, sort_keys=True)
  92. # Write back the result which will contain all fields filled in and
  93. # any post processing done on the log data
  94. with open(args.error_file, "w") as json_fp:
  95. if data:
  96. json_fp.write(data)
  97. if args.assume_yes == False and edit_content(args.error_file):
  98. #We'll need to re-read the content if we edited it
  99. with open(args.error_file, 'r') as json_fp:
  100. data = json_fp.read()
  101. return data
  102. def send_data(data, args):
  103. headers={'Content-type': 'application/json', 'User-Agent': "send-error-report/"+version}
  104. if args.json:
  105. url = "http://"+args.server+"/ClientPost/JSON/"
  106. else:
  107. url = "http://"+args.server+"/ClientPost/"
  108. req = urllib2.Request(url, data=data, headers=headers)
  109. try:
  110. response = urllib2.urlopen(req)
  111. except urllib2.HTTPError, e:
  112. logging.error(e.reason)
  113. sys.exit(1)
  114. print response.read()
  115. if __name__ == '__main__':
  116. arg_parse = argparse.ArgumentParser(description="This scripts will send an error report to your specified error-report-web server.")
  117. arg_parse.add_argument("error_file",
  118. help="Generated error report file location",
  119. type=str)
  120. arg_parse.add_argument("-y",
  121. "--assume-yes",
  122. help="Assume yes to all queries and do not prompt",
  123. action="store_true")
  124. arg_parse.add_argument("-s",
  125. "--server",
  126. help="Server to send error report to",
  127. type=str,
  128. default="errors.yoctoproject.org")
  129. arg_parse.add_argument("-e",
  130. "--email",
  131. help="Email address to be used for contact",
  132. type=str,
  133. default="")
  134. arg_parse.add_argument("-n",
  135. "--name",
  136. help="Submitter name used to identify your error report",
  137. type=str,
  138. default="")
  139. arg_parse.add_argument("-l",
  140. "--link-back",
  141. help="A url to link back to this build from the error report server",
  142. type=str,
  143. default="")
  144. arg_parse.add_argument("-j",
  145. "--json",
  146. help="Return the result in json format, silences all other output",
  147. action="store_true")
  148. args = arg_parse.parse_args()
  149. if (args.json == False):
  150. print "Preparing to send errors to: "+args.server
  151. data = prepare_data(args)
  152. send_data(data, args)
  153. sys.exit(0)