mirror of
https://github.com/PiBrewing/craftbeerpi4.git
synced 2024-11-09 17:07:43 +01:00
log http endpoint added
This commit is contained in:
parent
8200c48dfc
commit
bbbfe92aab
12 changed files with 657 additions and 277 deletions
File diff suppressed because it is too large
Load diff
|
@ -38,6 +38,8 @@ class JobController(object):
|
||||||
|
|
||||||
self.cbpi.app.on_startup.append(spawn_job)
|
self.cbpi.app.on_startup.append(spawn_job)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def start_job(self, method, name, type):
|
async def start_job(self, method, name, type):
|
||||||
scheduler = get_scheduler_from_app(self.cbpi.app)
|
scheduler = get_scheduler_from_app(self.cbpi.app)
|
||||||
return await scheduler.spawn(method, name, type)
|
return await scheduler.spawn(method, name, type)
|
||||||
|
|
|
@ -5,6 +5,8 @@ import os
|
||||||
from logging.handlers import RotatingFileHandler
|
from logging.handlers import RotatingFileHandler
|
||||||
from time import strftime, localtime
|
from time import strftime, localtime
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
import zipfile
|
||||||
|
|
||||||
|
|
||||||
class LogController:
|
class LogController:
|
||||||
|
|
||||||
|
@ -50,6 +52,7 @@ class LogController:
|
||||||
# remove duplicates
|
# remove duplicates
|
||||||
names = set(names)
|
names = set(names)
|
||||||
|
|
||||||
|
print(names)
|
||||||
result = None
|
result = None
|
||||||
|
|
||||||
def dateparse(time_in_secs):
|
def dateparse(time_in_secs):
|
||||||
|
@ -89,6 +92,8 @@ class LogController:
|
||||||
data[name] = result[name].interpolate(limit_direction='both', limit=10).tolist()
|
data[name] = result[name].interpolate(limit_direction='both', limit=10).tolist()
|
||||||
else:
|
else:
|
||||||
data[name] = result.interpolate().tolist()
|
data[name] = result.interpolate().tolist()
|
||||||
|
|
||||||
|
print(data)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,9 +103,10 @@ class LogController:
|
||||||
:param name: log name as string. pattern /logs/sensor_%s.log*
|
:param name: log name as string. pattern /logs/sensor_%s.log*
|
||||||
:return: list of log file names
|
:return: list of log file names
|
||||||
'''
|
'''
|
||||||
return = glob.glob('./logs/sensor_%s.log*' % name)
|
|
||||||
|
|
||||||
async def clear_log(self, name:str ) -> str:
|
return [os.path.basename(x) for x in glob.glob('./logs/sensor_%s.log*' % name)]
|
||||||
|
|
||||||
|
def clear_log(self, name:str ) -> str:
|
||||||
'''
|
'''
|
||||||
|
|
||||||
:param name: log name as string. pattern /logs/sensor_%s.log*
|
:param name: log name as string. pattern /logs/sensor_%s.log*
|
||||||
|
@ -108,12 +114,48 @@ class LogController:
|
||||||
'''
|
'''
|
||||||
all_filenames = glob.glob('./logs/sensor_%s.log*' % name)
|
all_filenames = glob.glob('./logs/sensor_%s.log*' % name)
|
||||||
for f in all_filenames:
|
for f in all_filenames:
|
||||||
print(f)
|
|
||||||
os.remove(f)
|
os.remove(f)
|
||||||
|
|
||||||
if name in self.datalogger:
|
if name in self.datalogger:
|
||||||
del self.datalogger[name]
|
del self.datalogger[name]
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_zip_file_names(self, name: str) -> list:
|
||||||
|
|
||||||
|
'''
|
||||||
|
Return a list of all zip file names
|
||||||
|
:param name:
|
||||||
|
:return:
|
||||||
|
'''
|
||||||
|
|
||||||
|
return [os.path.basename(x) for x in glob.glob('./logs/*-sensor-%s.zip' % name)]
|
||||||
|
|
||||||
|
def clear_zip(self, name:str ) -> None:
|
||||||
|
"""
|
||||||
|
clear all zip files for a sensor
|
||||||
|
:param name: sensor name
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
|
||||||
|
all_filenames = glob.glob('./logs/*-sensor-%s.zip' % name)
|
||||||
|
for f in all_filenames:
|
||||||
|
os.remove(f)
|
||||||
|
|
||||||
|
def zip_log_data(self, name: str) -> str:
|
||||||
|
"""
|
||||||
|
:param name: sensor name
|
||||||
|
:return: zip_file_name
|
||||||
|
"""
|
||||||
|
|
||||||
|
formatted_time = strftime("%Y-%m-%d-%H_%M_%S", localtime())
|
||||||
|
file_name = './logs/%s-sensor-%s.zip' % (formatted_time, name)
|
||||||
|
zip = zipfile.ZipFile(file_name, 'w', zipfile.ZIP_DEFLATED)
|
||||||
|
all_filenames = glob.glob('./logs/sensor_%s.log*' % name)
|
||||||
|
for f in all_filenames:
|
||||||
|
zip.write(os.path.join(f))
|
||||||
|
zip.close()
|
||||||
|
|
||||||
|
return file_name
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ from cbpi.controller.translation_controller import TranslationController
|
||||||
from cbpi.http_endpoints.http_translation import TranslationHttpEndpoint
|
from cbpi.http_endpoints.http_translation import TranslationHttpEndpoint
|
||||||
from cbpi.http_endpoints.http_plugin import PluginHttpEndpoints
|
from cbpi.http_endpoints.http_plugin import PluginHttpEndpoints
|
||||||
from cbpi.http_endpoints.http_system import SystemHttpEndpoints
|
from cbpi.http_endpoints.http_system import SystemHttpEndpoints
|
||||||
|
from cbpi.http_endpoints.http_log import LogHttpEndpoints
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -104,6 +105,7 @@ class CraftBeerPi():
|
||||||
self.http_plugin = PluginHttpEndpoints(self)
|
self.http_plugin = PluginHttpEndpoints(self)
|
||||||
self.http_system = SystemHttpEndpoints(self)
|
self.http_system = SystemHttpEndpoints(self)
|
||||||
self.notification = NotificationController(self)
|
self.notification = NotificationController(self)
|
||||||
|
self.http_log = LogHttpEndpoints(self)
|
||||||
self.login = Login(self)
|
self.login = Login(self)
|
||||||
|
|
||||||
def _setup_shutdownhook(self):
|
def _setup_shutdownhook(self):
|
||||||
|
|
|
@ -31,8 +31,6 @@ class CustomSensor(CBPiSensor):
|
||||||
def get_state(self):
|
def get_state(self):
|
||||||
return self.state
|
return self.state
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_value(self):
|
def get_value(self):
|
||||||
|
|
||||||
return self.value
|
return self.value
|
||||||
|
|
|
@ -21,7 +21,6 @@ class CBPiMqttClient:
|
||||||
|
|
||||||
async def listen(self, topic, **kwargs):
|
async def listen(self, topic, **kwargs):
|
||||||
if self.client is not None:
|
if self.client is not None:
|
||||||
print(topic, kwargs)
|
|
||||||
await self.client.publish(topic, str.encode(json.dumps(kwargs, cls=ComplexEncoder)), QOS_0)
|
await self.client.publish(topic, str.encode(json.dumps(kwargs, cls=ComplexEncoder)), QOS_0)
|
||||||
|
|
||||||
def setup(cbpi):
|
def setup(cbpi):
|
||||||
|
@ -32,5 +31,5 @@ def setup(cbpi):
|
||||||
:param cbpi: the cbpi core
|
:param cbpi: the cbpi core
|
||||||
:return:
|
:return:
|
||||||
'''
|
'''
|
||||||
print("MQTT REGISTER-------------")
|
client = CBPiMqttClient(cbpi)
|
||||||
c = CBPiMqttClient(cbpi)
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
name: MQTT
|
name: MQTT
|
||||||
version: 4.0
|
version: 4.0
|
||||||
active: false
|
active: False
|
63
cbpi/http_endpoints/http_log.py
Normal file
63
cbpi/http_endpoints/http_log.py
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
from aiohttp import web
|
||||||
|
from cbpi.utils.utils import json_dumps
|
||||||
|
from cbpi.api import request_mapping
|
||||||
|
|
||||||
|
class LogHttpEndpoints:
|
||||||
|
|
||||||
|
def __init__(self,cbpi):
|
||||||
|
self.cbpi = cbpi
|
||||||
|
self.cbpi.register(self, url_prefix="/log")
|
||||||
|
|
||||||
|
@request_mapping(path="/{name}/zip", method="POST", auth_required=False)
|
||||||
|
async def create_zip_names(self, request):
|
||||||
|
log_name = request.match_info['name']
|
||||||
|
data = self.cbpi.log.zip_log_data(log_name)
|
||||||
|
print(data)
|
||||||
|
return web.json_response(dict(filename=data), dumps=json_dumps)
|
||||||
|
|
||||||
|
@request_mapping(path="/{name}/zip", method="DELETE", auth_required=False)
|
||||||
|
async def clear_zip_names(self, request):
|
||||||
|
log_name = request.match_info['name']
|
||||||
|
self.cbpi.log.clear_zip(log_name)
|
||||||
|
return web.Response(status=204)
|
||||||
|
|
||||||
|
@request_mapping(path="/zip/download/{name}", method="GET", auth_required=False)
|
||||||
|
async def download_zip(self, request):
|
||||||
|
response = web.StreamResponse(
|
||||||
|
status=200,
|
||||||
|
reason='OK',
|
||||||
|
headers={'Content-Type': 'application/zip'},
|
||||||
|
)
|
||||||
|
await response.prepare(request)
|
||||||
|
log_name = request.match_info['name']
|
||||||
|
with open('./logs/%s.zip' % log_name, 'rb') as file:
|
||||||
|
for line in file.readlines():
|
||||||
|
await response.write(line)
|
||||||
|
|
||||||
|
await response.write_eof()
|
||||||
|
return response
|
||||||
|
|
||||||
|
@request_mapping(path="/{name}/zip", method="GET", auth_required=False)
|
||||||
|
async def get_zip_names(self, request):
|
||||||
|
log_name = request.match_info['name']
|
||||||
|
data = self.cbpi.log.get_all_zip_file_names(log_name)
|
||||||
|
return web.json_response(data, dumps=json_dumps)
|
||||||
|
|
||||||
|
@request_mapping(path="/{name}/files", method="GET", auth_required=False)
|
||||||
|
async def get_file_names(self, request):
|
||||||
|
log_name = request.match_info['name']
|
||||||
|
print(log_name)
|
||||||
|
data = self.cbpi.log.get_logfile_names(log_name)
|
||||||
|
return web.json_response(data, dumps=json_dumps)
|
||||||
|
|
||||||
|
@request_mapping(path="/{name}", method="GET", auth_required=False)
|
||||||
|
async def delete_log(self, request):
|
||||||
|
log_name = request.match_info['name']
|
||||||
|
data = await self.cbpi.log.get_data(log_name)
|
||||||
|
return web.json_response(data, dumps=json_dumps)
|
||||||
|
|
||||||
|
@request_mapping(path="/{name}", method="DELETE", auth_required=False)
|
||||||
|
async def delete_all_logs(self, request):
|
||||||
|
log_name = request.match_info['name']
|
||||||
|
await self.cbpi.log.clear_logs(log_name)
|
||||||
|
return web.Response(status=204)
|
|
@ -1,3 +1,4 @@
|
||||||
|
import datetime
|
||||||
from json import JSONEncoder
|
from json import JSONEncoder
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,6 +9,8 @@ class ComplexEncoder(JSONEncoder):
|
||||||
|
|
||||||
if hasattr(obj, "to_json") and callable(getattr(obj, "to_json")):
|
if hasattr(obj, "to_json") and callable(getattr(obj, "to_json")):
|
||||||
return obj.to_json()
|
return obj.to_json()
|
||||||
|
elif isinstance(obj, datetime.datetime):
|
||||||
|
return obj.__str__()
|
||||||
else:
|
else:
|
||||||
raise TypeError()
|
raise TypeError()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import logging
|
import logging
|
||||||
import re
|
|
||||||
import weakref
|
import weakref
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
from aiohttp import web
|
from aiohttp import web
|
||||||
from cbpi.api import *
|
|
||||||
from voluptuous import Schema
|
from voluptuous import Schema
|
||||||
|
|
||||||
from cbpi.utils import json_dumps
|
from cbpi.utils import json_dumps
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
pandas
|
||||||
aiohttp==3.4.4
|
aiohttp==3.4.4
|
||||||
aiohttp-auth==0.1.1
|
aiohttp-auth==0.1.1
|
||||||
aiohttp-route-decorator==0.1.4
|
aiohttp-route-decorator==0.1.4
|
||||||
|
|
|
@ -18,7 +18,7 @@ class UtilsTestCase(AioHTTPTestCase):
|
||||||
|
|
||||||
log_name = "test"
|
log_name = "test"
|
||||||
#clear all logs
|
#clear all logs
|
||||||
await self.cbpi.log.clear_log(log_name)
|
self.cbpi.log.clear_log(log_name)
|
||||||
assert len(glob.glob('./logs/sensor_%s.log*' % log_name)) == 0
|
assert len(glob.glob('./logs/sensor_%s.log*' % log_name)) == 0
|
||||||
|
|
||||||
# write log entries
|
# write log entries
|
||||||
|
@ -29,11 +29,13 @@ class UtilsTestCase(AioHTTPTestCase):
|
||||||
|
|
||||||
# read log data
|
# read log data
|
||||||
data = await self.cbpi.log.get_data(log_name, sample_rate='1s')
|
data = await self.cbpi.log.get_data(log_name, sample_rate='1s')
|
||||||
|
|
||||||
|
|
||||||
assert len(data["time"]) == 5
|
assert len(data["time"]) == 5
|
||||||
|
|
||||||
await self.cbpi.log.clear_log(log_name)
|
assert self.cbpi.log.zip_log_data(log_name) is not None
|
||||||
|
|
||||||
|
self.cbpi.log.clear_zip(log_name)
|
||||||
|
|
||||||
|
self.cbpi.log.clear_log(log_name)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue