You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 line
6.0KB

  1. import datetime
  2. import os
  3. import time
  4. import requests
  5. import logging
  6. from flask import request, send_from_directory, json
  7. from flask_classy import FlaskView, route
  8. from modules import cbpi
  9. class LogView(FlaskView):
  10. def __init__(self):
  11. self.logger = logging.getLogger(__name__)
  12. @route('/', methods=['GET'])
  13. def get_all_logfiles(self):
  14. result = []
  15. for filename in os.listdir("./logs"):
  16. if filename.endswith(".log"):
  17. result.append(filename)
  18. return json.dumps(result)
  19. @route('/actions')
  20. def actions(self):
  21. filename = "./logs/action.log"
  22. if not os.path.isfile(filename):
  23. self.logger.warn("File does not exist [%s]", filename)
  24. return json.dumps([])
  25. import csv
  26. array = []
  27. with open(filename, 'rb') as f:
  28. reader = csv.reader(f)
  29. for row in reader:
  30. try:
  31. time.mktime(time.strptime(row[0], "%Y-%m-%d %H:%M:%S"))
  32. array.append([int(time.mktime(time.strptime(row[0], "%Y-%m-%d %H:%M:%S")) * 1000), row[1]])
  33. except:
  34. pass
  35. json_dumps = json.dumps(array)
  36. self.logger.debug("Loaded action.log [%s]", json_dumps)
  37. return json_dumps
  38. @route('/<file>', methods=["DELETE"])
  39. def clearlog(self, file):
  40. """
  41. Overload delete method to shutdown sensor before delete
  42. :param id: sensor id
  43. :return: HTTP 204
  44. """
  45. if not self.check_filename(file):
  46. return ('File Not Found', 404)
  47. filename = "./logs/%s" % file
  48. if os.path.isfile(filename) == True:
  49. os.remove(filename)
  50. cbpi.notify("log deleted succesfully", "")
  51. else:
  52. cbpi.notify("Failed to delete log", "", type="danger")
  53. return ('', 204)
  54. def querry_tsdb(self, type, id):
  55. kairosdb_server = "http://127.0.0.1:" + cbpi.cache["config"]["kairos_db_port"].__dict__["value"]
  56. if cbpi.cache["active_brew"] != "" and cbpi.cache["active_brew"] != "none":
  57. tag = '"brew": "%s"' % cbpi.cache["active_brew"]
  58. else:
  59. tag = ""
  60. data = dict(metrics=[
  61. {
  62. "tags": {tag},
  63. "name": "cbpi.%s_%s" % (type, id),
  64. "aggregators": [
  65. {
  66. "name": "avg",
  67. "align_sampling": True,
  68. "sampling": {
  69. "value": "5",
  70. "unit": "seconds"
  71. },
  72. "align_start_time": True
  73. }
  74. ]
  75. }
  76. ],
  77. cache_time=0,
  78. start_relative={
  79. "value": "1",
  80. "unit": "days"
  81. })
  82. self.logger.debug("query: %s", json.dumps(data))
  83. response = requests.post(kairosdb_server + "/api/v1/datapoints/query", json.dumps(data))
  84. if response.ok:
  85. self.logger.debug("Fetching time series for [%s_%s] took [%s]", type, id, response.elapsed)
  86. self.logger.debug("Time series for [%s_%s] is [%s]", type, id, response.json())
  87. return response.json()["queries"][0]["results"][0]["values"]
  88. else:
  89. self.logger.warning("Failed to fetch time series for [%s_%s]. Response [%s]", type, id, response)
  90. def querry_log(self, type, id):
  91. filename = "./logs/%s_%s.log" % (type, id)
  92. if os.path.isfile(filename) == False:
  93. return
  94. import csv
  95. array = []
  96. with open(filename, 'rb') as f:
  97. reader = csv.reader(f)
  98. for row in reader:
  99. try:
  100. array.append([int((datetime.datetime.strptime(row[0], "%Y-%m-%d %H:%M:%S") - datetime.datetime(1970,
  101. 1,
  102. 1)).total_seconds()) * 1000,
  103. float(row[1])])
  104. except:
  105. pass
  106. return array
  107. def read_log_as_json(self, type, id):
  108. use_kairosdb = (cbpi.cache["config"]["kairos_db"].__dict__["value"] == "YES")
  109. if use_kairosdb:
  110. return self.querry_tsdb(type, id)
  111. else:
  112. return self.querry_log(type, id)
  113. def convert_chart_data_to_json(self, chart_data):
  114. return {"name": chart_data["name"],
  115. "data": self.read_log_as_json(chart_data["data_type"], chart_data["data_id"])}
  116. @route('/<t>/<int:id>', methods=["POST"])
  117. def get_logs_as_json(self, t, id):
  118. data = request.json
  119. result = []
  120. if t == "s":
  121. name = cbpi.cache.get("sensors").get(id).name
  122. result.append({"name": name, "data": self.read_log_as_json("sensor", id)})
  123. if t == "k":
  124. kettle = cbpi.cache.get("kettle").get(id)
  125. result = map(self.convert_chart_data_to_json, cbpi.get_controller(kettle.logic).get("class").chart(kettle))
  126. if t == "f":
  127. fermenter = cbpi.cache.get("fermenter").get(id)
  128. result = map(self.convert_chart_data_to_json,
  129. cbpi.get_fermentation_controller(fermenter.logic).get("class").chart(fermenter))
  130. return json.dumps(result)
  131. @route('/download/<file>')
  132. @cbpi.nocache
  133. def download(self, file):
  134. if not self.check_filename(file):
  135. return ('File Not Found', 404)
  136. return send_from_directory('../logs', file, as_attachment=True, attachment_filename=file)
  137. def check_filename(self, name):
  138. import re
  139. pattern = re.compile('^([A-Za-z0-9-_])+.log$')
  140. return True if pattern.match(name) else False
  141. @cbpi.initalizer()
  142. def init(app):
  143. """
  144. Initializer for the message module
  145. :param app: the flask app
  146. :return: None
  147. """
  148. LogView.register(cbpi.app, route_base='/api/logs')