limit.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. '''
  2. Created on 29/01/2013
  3. @author: konstaa
  4. '''
  5. import logging
  6. import time
  7. import core.log
  8. import core.db.loader
  9. import core.db.post
  10. import core.db.utils
  11. import core.export.cout
  12. import core.warn
  13. import core.cmdparser
  14. def main():
  15. exit_code = 0
  16. log_plugin = core.log.Plugin()
  17. db_plugin = core.db.post.Plugin()
  18. warn_plugin = core.warn.Plugin()
  19. parser = core.cmdparser.MultiOptionParser(usage="Usage: %prog [options] -- <path 1> ... <path N>")
  20. log_plugin.declare_configuration(parser)
  21. db_plugin.declare_configuration(parser)
  22. warn_plugin.declare_configuration(parser)
  23. (options, args) = parser.parse_args()
  24. log_plugin.configure(options)
  25. db_plugin.configure(options)
  26. warn_plugin.configure(options)
  27. loader_prev = core.db.loader.Loader()
  28. if db_plugin.dbfile_prev != None:
  29. loader_prev.open_database(db_plugin.dbfile_prev)
  30. loader = core.db.loader.Loader()
  31. loader.open_database(db_plugin.dbfile)
  32. warn_plugin.verify_namespaces(loader.iterate_namespace_names())
  33. for each in loader.iterate_namespace_names():
  34. warn_plugin.verify_fields(each, loader.get_namespace(each).iterate_field_names())
  35. paths = None
  36. if len(args) == 0:
  37. paths = [""]
  38. else:
  39. paths = args
  40. # Try to optimise iterative change scans
  41. modified_file_ids = None
  42. if warn_plugin.mode != warn_plugin.MODE_ALL:
  43. modified_file_ids = get_list_of_modified_files(loader, loader_prev)
  44. for path in paths:
  45. logging.info("Processing: " + path)
  46. for limit in warn_plugin.iterate_limits():
  47. logging.info("Applying limit: " + str(limit))
  48. filters = [limit.filter]
  49. if modified_file_ids != None:
  50. filters.append(('file_id', 'IN', modified_file_ids))
  51. selected_data = loader.load_selected_data(limit.namespace,
  52. fields = [limit.field],
  53. path=path,
  54. filters = filters)
  55. if selected_data == None:
  56. logging.error("Specified path '" + path + "' is invalid (not found in the database records)")
  57. exit_code += 1
  58. continue
  59. for select_data in selected_data:
  60. is_modified = None
  61. diff = None
  62. file_data = loader.load_file_data(select_data.get_path())
  63. file_data_prev = loader_prev.load_file_data(select_data.get_path())
  64. if file_data_prev != None:
  65. if file_data.get_checksum() == file_data_prev.get_checksum():
  66. diff = 0
  67. is_modified = False
  68. else:
  69. matcher = core.db.utils.FileRegionsMatcher(file_data, file_data_prev)
  70. prev_id = matcher.get_prev_id(select_data.get_region().get_id())
  71. if matcher.is_matched(select_data.get_region().get_id()):
  72. if matcher.is_modified(select_data.get_region().get_id()):
  73. is_modified = True
  74. else:
  75. is_modified = False
  76. diff = core.db.loader.DiffData(select_data,
  77. file_data_prev.get_region(prev_id)).get_data(limit.namespace, limit.field)
  78. if warn_plugin.is_mode_matched(limit.limit, select_data.get_data(limit.namespace, limit.field), diff, is_modified):
  79. exit_code += 1
  80. region_cursor = 0
  81. region_name = ""
  82. if select_data.get_region() != None:
  83. region_cursor = select_data.get_region().cursor
  84. region_name = select_data.get_region().name
  85. report_limit_exceeded(select_data.get_path(),
  86. region_cursor,
  87. limit.namespace,
  88. limit.field,
  89. region_name,
  90. select_data.get_data(limit.namespace, limit.field),
  91. diff,
  92. limit.limit,
  93. is_modified)
  94. return exit_code
  95. def get_list_of_modified_files(loader, loader_prev):
  96. modified_file_ids = []
  97. logging.info("Identifying changed files...")
  98. old_files_map = {}
  99. for each in loader_prev.iterate_file_data():
  100. old_files_map[each.get_path()] = each.get_checksum()
  101. if len(old_files_map) == 0:
  102. return None
  103. for each in loader.iterate_file_data():
  104. if len(modified_file_ids) > 1000: # If more than 1000 files changed, skip optimisation
  105. modified_file_ids = None
  106. break
  107. if (each.get_path() not in old_files_map.keys()) or old_files_map[each.get_path()] != each.get_checksum():
  108. modified_file_ids.append(each.get_id())
  109. if modified_file_ids != None:
  110. modified_file_ids = " , ".join(modified_file_ids)
  111. modified_file_ids = "(" + modified_file_ids + ")"
  112. old_files_map = None
  113. return modified_file_ids
  114. def report_limit_exceeded(path, cursor, namespace, field, region_name, stat_level, trend_value, stat_limit, is_modified):
  115. message = "Metric '" + namespace + "/" + field + "' for region '" + region_name + "' exceeds the limit."
  116. details = [("Metric name", namespace + "/" + field),
  117. ("Region name", region_name),
  118. ("Metric value", stat_level),
  119. ("Modified", is_modified),
  120. ("Change trend", '{0:{1}}'.format(trend_value, '+' if trend_value else '')),
  121. ("Limit", stat_limit)]
  122. core.export.cout.cout(path, cursor, core.export.cout.SEVERITY_WARNING, message, details)
  123. if __name__ == '__main__':
  124. ts = time.time()
  125. core.log.set_default_format()
  126. exit_code = main()
  127. logging.warning("Exit code: " + str(exit_code) + ". Time spent: " + str(round((time.time() - ts), 2)) + " seconds. Done")
  128. exit(exit_code)