Compare commits

...

11 Commits

Author SHA1 Message Date
pedro a67fda6b51 better printing of DOMAIN var
when in settings, any command prints again DOMAIN which is boring and
inefficient
2024-11-05 04:01:44 +01:00
pedro 79a34c9b55 logger: always do traceback when DEBUG var is True
related to #13
2024-11-05 03:43:18 +01:00
Cayo Puigdefabregas e4124fb20b fix duplicate logs 2024-10-31 15:25:38 +01:00
pedro 517c3eb0c0 DEBUG false -> true
we are not ready to deploy without DEBUG

- collect static is not configured
- current demo in debug helps to find problems easily
2024-10-31 15:04:28 +01:00
pedro d4f50961bc improve logging text for certain messages 2024-10-31 14:24:16 +01:00
Cayo Puigdefabregas 65bd88a2a2 table in evidence page details 2024-10-31 13:15:56 +01:00
Cayo Puigdefabregas 7926943947 remove dashboard.js in login template 2024-10-31 12:51:49 +01:00
pedro 9de7dc6647 docker: disable debug by default 2024-10-31 11:57:33 +01:00
Cayo Puigdefabregas 16ba03bd0a fix 2024-10-31 10:40:53 +01:00
Cayo Puigdefabregas 4b3471d24e fix bug 2024-10-31 10:24:15 +01:00
Cayo Puigdefabregas e74ddc47a7 extract logs with colors and depending of DEBUG var 2024-10-31 10:14:02 +01:00
13 changed files with 158 additions and 67 deletions

View File

@ -1,11 +1,12 @@
DOMAIN=localhost
DEMO=false
# note that with DEBUG=true, logs are more verbose (include tracebacks)
DEBUG=true
DEMO=true
STATIC_ROOT=/tmp/static/
MEDIA_ROOT=/tmp/media/
ALLOWED_HOSTS=localhost,localhost:8000,127.0.0.1,
DOMAIN=localhost
DEBUG=True
EMAIL_HOST="mail.example.org"
EMAIL_HOST_USER="fillme_noreply"
EMAIL_HOST_PASSWORD="fillme_passwd"

View File

@ -5,6 +5,7 @@ import logging
from uuid import uuid4
from django.urls import reverse_lazy
from django.conf import settings
from django.http import JsonResponse
from django.shortcuts import get_object_or_404, redirect
from django.utils.translation import gettext_lazy as _
@ -41,20 +42,20 @@ class ApiMixing(View):
# Authentication
auth_header = self.request.headers.get('Authorization')
if not auth_header or not auth_header.startswith('Bearer '):
logger.exception("Invalid or missing token {}".format(auth_header))
logger.error("Invalid or missing token %s", auth_header)
return JsonResponse({'error': 'Invalid or missing token'}, status=401)
token = auth_header.split(' ')[1].strip("'").strip('"')
try:
uuid.UUID(token)
except Exception:
logger.exception("Invalid token {}".format(token))
logger.error("Invalid or missing token %s", token)
return JsonResponse({'error': 'Invalid or missing token'}, status=401)
self.tk = Token.objects.filter(token=token).first()
if not self.tk:
logger.exception("Invalid or missing token {}".format(token))
logger.error("Invalid or missing token %s", token)
return JsonResponse({'error': 'Invalid or missing token'}, status=401)
@ -72,7 +73,8 @@ class NewSnapshotView(ApiMixing):
try:
data = json.loads(request.body)
except json.JSONDecodeError:
logger.exception("Invalid Snapshot of user {}".format(self.tk.owner))
txt = "error: the snapshot is not a json"
logger.error("%s", txt)
return JsonResponse({'error': 'Invalid JSON'}, status=500)
# Process snapshot
@ -85,7 +87,7 @@ class NewSnapshotView(ApiMixing):
if not data.get("uuid"):
txt = "error: the snapshot not have uuid"
logger.exception(txt)
logger.error("%s", txt)
return JsonResponse({'status': txt}, status=500)
exist_annotation = Annotation.objects.filter(
@ -94,15 +96,20 @@ class NewSnapshotView(ApiMixing):
if exist_annotation:
txt = "error: the snapshot {} exist".format(data['uuid'])
logger.exception(txt)
logger.warning("%s", txt)
return JsonResponse({'status': txt}, status=500)
try:
Build(data, self.tk.owner)
except Exception as err:
logger.exception(err)
return JsonResponse({'status': f"fail: {err}"}, status=500)
if settings.DEBUG:
logger.exception("%s", err)
snapshot_id = data.get("uuid", "")
txt = "It is not possible to parse snapshot: %s."
logger.error(txt, snapshot_id)
text = "fail: It is not possible to parse snapshot"
return JsonResponse({'status': text}, status=500)
annotation = Annotation.objects.filter(
uuid=data['uuid'],
@ -114,7 +121,7 @@ class NewSnapshotView(ApiMixing):
if not annotation:
logger.exception("Error: No annotation for uuid: {}".format(data["uuid"]))
logger.error("Error: No annotation for uuid: %s", data["uuid"])
return JsonResponse({'status': 'fail'}, status=500)
url_args = reverse_lazy("device:details", args=(annotation.value,))
@ -286,7 +293,7 @@ class AddAnnotationView(ApiMixing):
key = data["key"]
value = data["value"]
except Exception:
logger.exception("Invalid Snapshot of user {}".format(self.tk.owner))
logger.error("Invalid Snapshot of user %s", self.tk.owner)
return JsonResponse({'error': 'Invalid JSON'}, status=500)
Annotation.objects.create(

View File

@ -17,6 +17,8 @@ from pathlib import Path
from django.contrib.messages import constants as messages
from decouple import config, Csv
from utils.logger import CustomFormatter
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
@ -32,8 +34,6 @@ DEBUG = config('DEBUG', default=False, cast=bool)
DOMAIN = config("DOMAIN")
assert DOMAIN not in [None, ''], "DOMAIN var is MANDATORY"
# this var is very important, we print it
print("DOMAIN: " + DOMAIN)
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=DOMAIN, cast=Csv())
assert DOMAIN in ALLOWED_HOSTS, f"DOMAIN {DOMAIN} is not in ALLOWED_HOSTS {ALLOWED_HOSTS}"
@ -205,12 +205,34 @@ LOGOUT_REDIRECT_URL = '/'
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
'formatters': {
'colored': {
'()': CustomFormatter,
'format': '%(levelname)s %(asctime)s %(message)s'
},
},
"handlers": {
"console": {"level": "DEBUG", "class": "logging.StreamHandler"},
"console": {
"level": "DEBUG",
"class": "logging.StreamHandler",
"formatter": "colored"
},
},
"root": {
"handlers": ["console"],
"level": "DEBUG",
},
"loggers": {
"django": {
"handlers": ["console"],
"level": "INFO",
"propagate": False, # Asegura que no se reenvíen a los manejadores raíz
},
"django.request": {
"handlers": ["console"],
"level": "ERROR",
"propagate": False,
}
}
}

View File

@ -4,7 +4,7 @@ services:
build:
dockerfile: docker/devicehub-django.Dockerfile
environment:
- DEBUG=true
- DEBUG=${DEBUG:-false}
- DOMAIN=${DOMAIN:-localhost}
- ALLOWED_HOSTS=${ALLOWED_HOSTS:-$DOMAIN}
- DEMO=${DEMO:-false}

View File

@ -18,6 +18,8 @@ deploy() {
if [ "${DEBUG:-}" = 'true' ]; then
./manage.py print_settings
else
echo "DOMAIN: ${DOMAIN}"
fi
# detect if existing deployment (TODO only works with sqlite)

View File

@ -36,10 +36,8 @@ class Command(BaseCommand):
continue
user = institution.user_set.filter(is_admin=True).first()
if not user:
txt = "Error No there are Admins for the institution: {}".format(
institution.name
)
logger.exception(txt)
txt = "No there are Admins for the institution: %s"
logger.warning(txt, institution.name)
continue
snapshots_path = os.path.join(filepath, "snapshots")
@ -74,13 +72,12 @@ class Command(BaseCommand):
create_index(s, user)
create_annotation(s, user, commit=True)
except Exception as err:
txt = "Error: in placeholder {} \n{}".format(f_path, err)
logger.exception(txt)
txt = "In placeholder %s \n%s"
logger.warning(txt, f_path, err)
def build_snapshot(self, s, user, f_path):
try:
Build(s, user)
except Exception as err:
txt = "Error: in Snapshot {} \n{}".format(f_path, err)
logger.exception(txt)
except Exception:
txt = "Error: in Snapshot {}".format(f_path)
logger.error(txt)

View File

@ -4,6 +4,9 @@ import logging
from django.core.management.base import BaseCommand
from django.contrib.auth import get_user_model
from django.conf import settings
from utils.save_snapshots import move_json, save_in_disk
from evidence.parse import Build
@ -46,12 +49,15 @@ class Command(BaseCommand):
def open(self, filepath):
with open(filepath, 'r') as file:
content = json.loads(file.read())
self.snapshots.append(content)
path_name = save_in_disk(content, self.user.institution.name)
self.snapshots.append((content, path_name))
def parsing(self):
for s in self.snapshots:
for s, p in self.snapshots:
try:
self.devices.append(Build(s, self.user))
move_json(p, self.user.institution.name)
except Exception as err:
logger.exception(err)
snapshot_id = s.get("uuid", "")
txt = "Could not parse snapshot: %s"
logger.error(txt, snapshot_id)

View File

@ -33,7 +33,7 @@ def get_mac(lshw):
try:
get_network_cards(hw, nets)
except Exception as ss:
print("WARNING!! {}".format(ss))
logger.warning("%s", ss)
return
nets_sorted = sorted(nets, key=lambda x: x['businfo'])
@ -90,8 +90,8 @@ class Build:
)
if annotation:
txt = "Warning: Snapshot {} exist as annotation !!".format(self.uuid)
logger.exception(txt)
txt = "Warning: Snapshot %s already registered (annotation exists)"
logger.warning(txt, self.uuid)
return
for k, v in self.algorithms.items():
@ -135,9 +135,7 @@ class Build:
# mac = get_mac2(hwinfo_raw) or ""
mac = get_mac(lshw) or ""
if not mac:
print(f"WARNING: Could not retrieve MAC address in snapshot {snapshot['uuid']}" )
# TODO generate system annotation for that snapshot
else:
print(f"{manufacturer}{model}{chassis}{serial_number}{sku}{mac}")
txt = "Could not retrieve MAC address in snapshot %s"
logger.warning(txt, snapshot['uuid'])
return f"{manufacturer}{model}{chassis}{serial_number}{sku}{mac}"

View File

@ -1,4 +1,5 @@
import json
import logging
import numpy as np
from datetime import datetime
@ -8,6 +9,9 @@ from json_repair import repair_json
from utils.constants import CHASSIS_DH, DATASTORAGEINTERFACE
logger = logging.getLogger('django')
def get_lshw_child(child, nets, component):
if child.get('id') == component:
nets.append(child)
@ -483,12 +487,12 @@ class ParseSnapshot:
if isinstance(x, str):
try:
try:
hw = json.loads(lshw)
hw = json.loads(x)
except json.decoder.JSONDecodeError:
hw = json.loads(repair_json(lshw))
hw = json.loads(repair_json(x))
return hw
except Exception as ss:
print("WARNING!! {}".format(ss))
logger.warning("%s", ss)
return {}
return x
@ -497,5 +501,5 @@ class ParseSnapshot:
return self._errors
logger.error(txt)
self._errors.append(txt)
self._errors.append("%s", txt)

View File

@ -29,26 +29,44 @@
<div class="tab-content pt-2">
<div class="tab-pane fade show active" id="device">
<h5 class="card-title">List of chids</h5>
<h5 class="card-title"></h5>
<div class="list-group col-6">
{% for snap in object.annotations %}
{% if snap.type == 0 %}
<div class="list-group-item">
<div class="d-flex w-100 justify-content-between">
<h5 class="mb-1"></h5>
<small class="text-muted">
{{ snap.created }}
</small>
</div>
<p class="mb-1">
{{ snap.key }}<br />
</p>
<small class="text-muted">
<a href="{% url 'device:details' snap.value %}">{{ snap.value }}</a>
</small>
</div>
{% endif %}
{% endfor %}
<table class="table">
<thead>
<tr>
<th scope="col" data-sortable="">
{% trans "Type" %}
</th>
<th scope="col" data-sortable="">
{% trans "Identificator" %}
</th>
<th scope="col" data-sortable="">
{% trans "Data" %}
</th>
</tr>
</thead>
{% for snap in object.annotations %}
<tbody>
{% if snap.type == 0 %}
<tr>
<td>
{{ snap.key }}
</td>
<td>
<small class="text-muted">
<a href="{% url 'device:details' snap.value %}">{{ snap.value }}</a>
</small>
</td>
<td>
<small class="text-muted">
{{ snap.created }}
</small>
</td>
</tr>
{% endif %}
</tbody>
{% endfor %}
</table>
</div>
</div>
<div class="tab-pane fade" id="tag">

View File

@ -110,7 +110,6 @@
<script src="/static/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons@4.28.0/dist/feather.min.js" integrity="sha384-uO3SXW5IuS1ZpFPKugNNWqTZRRglnUJK6UAZ/gxOX80nxEkN9NcGZTftn6RzhGWE" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.4/dist/Chart.min.js" integrity="sha384-zNy6FEbO50N+Cg5wap8IKA4M/ZnLJgzc6w2NqACZaK0u0FXfOWRRJOnQtpZun8ha" crossorigin="anonymous"></script>
<script src="/static/js/dashboard.js"></script>
<script>
const togglePassword = document.querySelector('#togglePassword');
const password = document.querySelector('#id_password');

View File

@ -88,8 +88,8 @@ def create_annotation(doc, user, commit=False):
)
if annotation:
txt = "Warning: Snapshot {} exist as annotation !!".format(doc["uuid"])
logger.exception(txt)
txt = "Warning: Snapshot %s already registered (annotation exists)"
logger.warning(txt, doc["uuid"])
return annotation
return Annotation.objects.create(**data)

37
utils/logger.py Normal file
View File

@ -0,0 +1,37 @@
import logging
from django.conf import settings
# Colors
RED = "\033[91m"
PURPLE = "\033[95m"
YELLOW = "\033[93m"
RESET = "\033[0m"
class CustomFormatter(logging.Formatter):
def format(self, record):
if record.levelname == "ERROR":
color = RED
elif record.levelname == "WARNING":
color = PURPLE
elif record.levelname in ["INFO", "DEBUG"]:
color = YELLOW
else:
color = RESET
record.levelname = f"{color}{record.levelname}{RESET}"
if record.args:
record.msg = self.highlight_args(record.msg, record.args, color)
record.args = ()
# provide trace when DEBUG config
if settings.DEBUG:
import traceback
print(traceback.format_exc())
return super().format(record)
def highlight_args(self, message, args, color):
highlighted_args = tuple(f"{color}{arg}{RESET}" for arg in args)
return message % highlighted_args