mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
[enh] Allow to display all operation logs with one command
This commit is contained in:
parent
60727e5fab
commit
ba01168684
4 changed files with 69 additions and 59 deletions
|
@ -1603,26 +1603,27 @@ hook:
|
|||
help: The directory from where the script will be executed
|
||||
|
||||
#############################
|
||||
# Journals #
|
||||
# Log #
|
||||
#############################
|
||||
journals:
|
||||
category_help: Manage debug journals
|
||||
log:
|
||||
category_help: Manage debug logs
|
||||
actions:
|
||||
|
||||
### journals_list()
|
||||
### log_list()
|
||||
list:
|
||||
action_help: List journals
|
||||
api: GET /journals
|
||||
action_help: List logs
|
||||
api: GET /logs
|
||||
arguments:
|
||||
-l:
|
||||
full: --limit
|
||||
help: Maximum number of journals per categories
|
||||
help: Maximum number of logs per categories
|
||||
type: int
|
||||
|
||||
### journals_display()
|
||||
### log_display()
|
||||
display:
|
||||
action_help: Display a journal content
|
||||
api: GET /journals/<file_name>
|
||||
action_help: Display a log content
|
||||
api: GET /logs/<file_name_list>
|
||||
arguments:
|
||||
file_name:
|
||||
help: Journal file name
|
||||
file_name_list:
|
||||
help: Log filenames for which to display the content
|
||||
nargs: "*"
|
||||
|
|
|
@ -205,7 +205,7 @@
|
|||
"invalid_url_format": "Invalid URL format",
|
||||
"ip6tables_unavailable": "You cannot play with ip6tables here. You are either in a container or your kernel does not support it",
|
||||
"iptables_unavailable": "You cannot play with iptables here. You are either in a container or your kernel does not support it",
|
||||
"journal_does_exists": "There is not journal with the name '{journal}', use 'yunohost journal list to see all available journals'",
|
||||
"log_does_exists": "There is not operation log with the name '{log}', use 'yunohost log list to see all available operation logs'",
|
||||
"ldap_init_failed_to_create_admin": "LDAP initialization failed to create admin user",
|
||||
"ldap_initialized": "LDAP has been initialized",
|
||||
"license_undefined": "undefined",
|
||||
|
|
|
@ -433,7 +433,7 @@ def app_change_url(auth, app, domain, path):
|
|||
|
||||
"""
|
||||
from yunohost.hook import hook_exec, hook_callback
|
||||
from yunohost.journals import Journal
|
||||
from yunohost.log import Journal
|
||||
|
||||
installed = _is_installed(app)
|
||||
if not installed:
|
||||
|
@ -542,7 +542,7 @@ def app_upgrade(auth, app=[], url=None, file=None):
|
|||
|
||||
"""
|
||||
from yunohost.hook import hook_add, hook_remove, hook_exec, hook_callback
|
||||
from yunohost.journals import Journal
|
||||
from yunohost.log import Journal
|
||||
|
||||
# Retrieve interface
|
||||
is_api = msettings.get('interface') == 'api'
|
||||
|
@ -673,7 +673,7 @@ def app_install(auth, app, label=None, args=None, no_remove_on_failure=False):
|
|||
|
||||
"""
|
||||
from yunohost.hook import hook_add, hook_remove, hook_exec, hook_callback
|
||||
from yunohost.journals import Journal
|
||||
from yunohost.log import Journal
|
||||
|
||||
# Fetch or extract sources
|
||||
try:
|
||||
|
@ -837,7 +837,7 @@ def app_remove(auth, app):
|
|||
|
||||
"""
|
||||
from yunohost.hook import hook_exec, hook_remove, hook_callback
|
||||
from yunohost.journals import Journal
|
||||
from yunohost.log import Journal
|
||||
|
||||
if not _is_installed(app):
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
|
|
|
@ -19,9 +19,9 @@
|
|||
|
||||
"""
|
||||
|
||||
""" yunohost_journals.py
|
||||
""" yunohost_log.py
|
||||
|
||||
Manage debug journals
|
||||
Manage debug logs
|
||||
"""
|
||||
|
||||
import os
|
||||
|
@ -34,90 +34,98 @@ from moulinette import m18n
|
|||
from moulinette.core import MoulinetteError
|
||||
from moulinette.utils.log import getActionLogger
|
||||
|
||||
JOURNALS_PATH = '/var/log/yunohost/journals/'
|
||||
OPERATIONS_PATH = '/var/log/yunohost/operation/'
|
||||
OPERATION_FILE_EXT = '.yml'
|
||||
|
||||
logger = getActionLogger('yunohost.journals')
|
||||
logger = getActionLogger('yunohost.log')
|
||||
|
||||
|
||||
def journals_list(limit=None):
|
||||
def log_list(limit=None):
|
||||
"""
|
||||
List available journals
|
||||
List available logs
|
||||
|
||||
Keyword argument:
|
||||
limit -- Maximum number of journals per categories
|
||||
limit -- Maximum number of logs per categories
|
||||
"""
|
||||
|
||||
result = {"categories": []}
|
||||
|
||||
if not os.path.exists(JOURNALS_PATH):
|
||||
if not os.path.exists(OPERATIONS_PATH):
|
||||
return result
|
||||
|
||||
for category in sorted(os.listdir(JOURNALS_PATH)):
|
||||
result["categories"].append({"name": category, "journals": []})
|
||||
for journal in filter(lambda x: x.endswith(".journal"), os.listdir(os.path.join(JOURNALS_PATH, category))):
|
||||
for category in sorted(os.listdir(OPERATIONS_PATH)):
|
||||
result["categories"].append({"name": category, "logs": []})
|
||||
for operation in filter(lambda x: x.endswith(OPERATION_FILE_EXT), os.listdir(os.path.join(OPERATIONS_PATH, category))):
|
||||
|
||||
file_name = journal
|
||||
file_name = operation
|
||||
|
||||
journal = journal[:-len(".journal")]
|
||||
journal = journal.split("_")
|
||||
operation = operation[:-len(OPERATION_FILE_EXT)]
|
||||
operation = operation.split("_")
|
||||
|
||||
journal_datetime = datetime.strptime(" ".join(journal[-2:]), "%Y-%m-%d %H-%M-%S")
|
||||
operation_datetime = datetime.strptime(" ".join(operation[-2:]), "%Y-%m-%d %H-%M-%S")
|
||||
|
||||
result["categories"][-1]["journals"].append({
|
||||
"started_at": journal_datetime,
|
||||
"name": " ".join(journal[:-2]),
|
||||
result["categories"][-1]["logs"].append({
|
||||
"started_at": operation_datetime,
|
||||
"name": " ".join(operation[:-2]),
|
||||
"file_name": file_name,
|
||||
"path": os.path.join(JOURNALS_PATH, category, file_name),
|
||||
"path": os.path.join(OPERATIONS_PATH, category, file_name),
|
||||
})
|
||||
|
||||
result["categories"][-1]["journals"] = list(reversed(sorted(result["categories"][-1]["journals"], key=lambda x: x["started_at"])))
|
||||
result["categories"][-1]["logs"] = list(reversed(sorted(result["categories"][-1]["logs"], key=lambda x: x["started_at"])))
|
||||
|
||||
if limit is not None:
|
||||
result["categories"][-1]["journals"] = result["categories"][-1]["journals"][:limit]
|
||||
result["categories"][-1]["logs"] = result["categories"][-1]["logs"][:limit]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def journals_display(file_name):
|
||||
def log_display(file_name_list):
|
||||
"""
|
||||
Display a journal content
|
||||
Display full log or specific logs listed
|
||||
|
||||
Argument:
|
||||
file_name
|
||||
file_name_list
|
||||
"""
|
||||
|
||||
if not os.path.exists(JOURNALS_PATH):
|
||||
if not os.path.exists(OPERATIONS_PATH):
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('journal_does_exists', journal=file_name))
|
||||
m18n.n('log_does_exists', log=" ".join(file_name_list)))
|
||||
|
||||
for category in os.listdir(JOURNALS_PATH):
|
||||
for journal in filter(lambda x: x.endswith(".journal"), os.listdir(os.path.join(JOURNALS_PATH, category))):
|
||||
if journal != file_name:
|
||||
result = {"logs": []}
|
||||
|
||||
for category in os.listdir(OPERATIONS_PATH):
|
||||
for operation in filter(lambda x: x.endswith(OPERATION_FILE_EXT), os.listdir(os.path.join(OPERATIONS_PATH, category))):
|
||||
if operation not in file_name_list and file_name_list:
|
||||
continue
|
||||
|
||||
with open(os.path.join(JOURNALS_PATH, category, file_name), "r") as content:
|
||||
file_name = operation
|
||||
|
||||
with open(os.path.join(OPERATIONS_PATH, category, file_name), "r") as content:
|
||||
content = content.read()
|
||||
|
||||
journal = journal[:-len(".journal")]
|
||||
journal = journal.split("_")
|
||||
journal_datetime = datetime.strptime(" ".join(journal[-2:]), "%Y-%m-%d %H-%M-%S")
|
||||
operation = operation[:-len(OPERATION_FILE_EXT)]
|
||||
operation = operation.split("_")
|
||||
operation_datetime = datetime.strptime(" ".join(operation[-2:]), "%Y-%m-%d %H-%M-%S")
|
||||
|
||||
infos, logs = content.split("\n---\n", 1)
|
||||
infos = yaml.safe_load(infos)
|
||||
logs = [{"datetime": x.split(": ", 1)[0].replace("_", " "), "line": x.split(": ", 1)[1]} for x in logs.split("\n") if x]
|
||||
|
||||
return {
|
||||
"started_at": journal_datetime,
|
||||
"name": " ".join(journal[:-2]),
|
||||
result['logs'].append({
|
||||
"started_at": operation_datetime,
|
||||
"name": " ".join(operation[:-2]),
|
||||
"file_name": file_name,
|
||||
"path": os.path.join(JOURNALS_PATH, category, file_name),
|
||||
"path": os.path.join(OPERATIONS_PATH, category, file_name),
|
||||
"metadata": infos,
|
||||
"logs": logs,
|
||||
}
|
||||
})
|
||||
|
||||
raise MoulinetteError(errno.EINVAL,
|
||||
m18n.n('journal_does_exists', journal=file_name))
|
||||
logger.debug("====> %s", len(file_name_list), exc_info=1)
|
||||
if len(file_name_list) > 0 and len(result['logs']) < len(file_name_list):
|
||||
logger.error(m18n.n('log_does_exists', log="', '".join(file_name_list)))
|
||||
|
||||
if len(result['logs']) > 0:
|
||||
return result
|
||||
|
||||
class Journal(object):
|
||||
def __init__(self, name, category, on_stdout=None, on_stderr=None, on_write=None, **kwargs):
|
||||
|
@ -129,7 +137,7 @@ class Journal(object):
|
|||
# this help uniformise file name and avoir threads concurrency errors
|
||||
self.started_at = datetime.now()
|
||||
|
||||
self.path = os.path.join(JOURNALS_PATH, category)
|
||||
self.path = os.path.join(OPERATIONS_PATH, category)
|
||||
|
||||
self.fd = None
|
||||
|
||||
|
@ -157,7 +165,8 @@ class Journal(object):
|
|||
if not os.path.exists(self.path):
|
||||
os.makedirs(self.path)
|
||||
|
||||
file_name = "%s_%s.journal" % (self.name if isinstance(self.name, basestring) else "_".join(self.name), self.started_at.strftime("%F_%X").replace(":", "-"))
|
||||
file_name = "%s_%s" % (self.name if isinstance(self.name, basestring) else "_".join(self.name), self.started_at.strftime("%F_%X").replace(":", "-"))
|
||||
file_name += OPERATION_FILE_EXT
|
||||
|
||||
serialized_additional_information = yaml.safe_dump(self.additional_information, default_flow_style=False)
|
||||
|
Loading…
Add table
Reference in a new issue